Merge remote-tracking branches 'spi/topic/mtk', 'spi/topic/pxa2xx', 'spi/topic/qspi...
authorMark Brown <broonie@kernel.org>
Mon, 31 Aug 2015 13:45:36 +0000 (14:45 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 31 Aug 2015 13:45:36 +0000 (14:45 +0100)
1609 files changed:
.get_maintainer.ignore [new file with mode: 0644]
.mailmap
Documentation/ABI/testing/sysfs-bus-iio
Documentation/DocBook/drm.tmpl
Documentation/arm/SPEAr/overview.txt
Documentation/arm/sunxi/README
Documentation/device-mapper/cache.txt
Documentation/device-mapper/thin-provisioning.txt
Documentation/devicetree/bindings/arm/cpus.txt
Documentation/devicetree/bindings/arm/sunxi.txt
Documentation/devicetree/bindings/dma/apm-xgene-dma.txt
Documentation/devicetree/bindings/drm/imx/fsl-imx-drm.txt
Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt
Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/phy/ti-phy.txt
Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt
Documentation/devicetree/bindings/sound/mt8173-max98090.txt
Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
Documentation/devicetree/bindings/spi/spi-ath79.txt
Documentation/devicetree/bindings/spi/spi-davinci.txt
Documentation/devicetree/bindings/spi/spi-img-spfi.txt
Documentation/devicetree/bindings/spi/spi-mt65xx.txt [new file with mode: 0644]
Documentation/hwmon/nct7904
Documentation/input/alps.txt
Documentation/kbuild/makefiles.txt
Documentation/power/swsusp.txt
Documentation/target/tcm_mod_builder.py
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/Kbuild
arch/alpha/include/asm/mm-arch-hooks.h [deleted file]
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/boot/dts/axc003.dtsi
arch/arc/boot/dts/axc003_idu.dtsi
arch/arc/include/asm/Kbuild
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/atomic.h
arch/arc/include/asm/bitops.h
arch/arc/include/asm/futex.h
arch/arc/include/asm/mm-arch-hooks.h [deleted file]
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/spinlock.h
arch/arc/include/asm/spinlock_types.h
arch/arc/include/uapi/asm/ptrace.h
arch/arc/kernel/intc-arcv2.c
arch/arc/kernel/intc-compact.c
arch/arc/kernel/mcip.c
arch/arc/kernel/setup.c
arch/arc/kernel/time.c
arch/arc/kernel/troubleshoot.c
arch/arc/lib/memcpy-archs.S
arch/arc/lib/memset-archs.S
arch/arc/mm/cache.c
arch/arc/mm/dma.c
arch/arc/plat-axs10x/axs10x.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/am335x-boneblack.dts
arch/arm/boot/dts/am335x-pepper.dts
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/atlas7.dtsi
arch/arm/boot/dts/cros-ec-keyboard.dtsi
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/dra72-evm.dts
arch/arm/boot/dts/exynos3250.dtsi
arch/arm/boot/dts/exynos4210-origen.dts
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/imx23.dtsi
arch/arm/boot/dts/imx25-pdk.dts
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx35.dtsi
arch/arm/boot/dts/imx51-apf51dev.dts
arch/arm/boot/dts/imx53-ard.dts
arch/arm/boot/dts/imx53-m53evk.dts
arch/arm/boot/dts/imx53-qsb-common.dtsi
arch/arm/boot/dts/imx53-smd.dts
arch/arm/boot/dts/imx53-tqma53.dtsi
arch/arm/boot/dts/imx53-tx53.dtsi
arch/arm/boot/dts/imx53-voipac-bsb.dts
arch/arm/boot/dts/imx6dl-riotboard.dts
arch/arm/boot/dts/imx6q-arm2.dts
arch/arm/boot/dts/imx6q-gk802.dts
arch/arm/boot/dts/imx6q-tbs2910.dts
arch/arm/boot/dts/imx6qdl-aristainetos.dtsi
arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
arch/arm/boot/dts/imx6qdl-rex.dtsi
arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
arch/arm/boot/dts/imx6qdl-sabresd.dtsi
arch/arm/boot/dts/imx6qdl-tx6.dtsi
arch/arm/boot/dts/imx6qdl-wandboard.dtsi
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6sl-evk.dts
arch/arm/boot/dts/imx6sx-sabreauto.dts
arch/arm/boot/dts/imx6sx-sdb.dtsi
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/k2e-clocks.dtsi
arch/arm/boot/dts/k2e.dtsi
arch/arm/boot/dts/k2hk-clocks.dtsi
arch/arm/boot/dts/k2hk.dtsi
arch/arm/boot/dts/k2l-clocks.dtsi
arch/arm/boot/dts/k2l.dtsi
arch/arm/boot/dts/keystone.dtsi
arch/arm/boot/dts/omap2430.dtsi
arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/socfpga_cyclone5_sockit.dts
arch/arm/boot/dts/spear1310-evb.dts
arch/arm/boot/dts/spear1310.dtsi
arch/arm/boot/dts/spear1340-evb.dts
arch/arm/boot/dts/spear1340.dtsi
arch/arm/boot/dts/spear13xx.dtsi
arch/arm/boot/dts/spear300-evb.dts
arch/arm/boot/dts/spear300.dtsi
arch/arm/boot/dts/spear310-evb.dts
arch/arm/boot/dts/spear310.dtsi
arch/arm/boot/dts/spear320-evb.dts
arch/arm/boot/dts/spear320.dtsi
arch/arm/boot/dts/spear3xx.dtsi
arch/arm/boot/dts/ste-ccu8540.dts
arch/arm/boot/dts/ste-ccu9540.dts
arch/arm/boot/dts/ste-dbx5x0.dtsi
arch/arm/boot/dts/ste-href.dtsi
arch/arm/boot/dts/ste-hrefprev60-stuib.dts
arch/arm/boot/dts/ste-hrefprev60-tvk.dts
arch/arm/boot/dts/ste-hrefprev60.dtsi
arch/arm/boot/dts/ste-hrefv60plus-stuib.dts
arch/arm/boot/dts/ste-hrefv60plus-tvk.dts
arch/arm/boot/dts/ste-hrefv60plus.dtsi
arch/arm/boot/dts/ste-nomadik-nhk15.dts
arch/arm/boot/dts/ste-nomadik-s8815.dts
arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
arch/arm/boot/dts/ste-snowball.dts
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/sunxi_defconfig
arch/arm/include/asm/Kbuild
arch/arm/include/asm/io.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/mm-arch-hooks.h [deleted file]
arch/arm/include/asm/pgtable-2level.h
arch/arm/kernel/armksyms.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/head.S
arch/arm/kernel/perf_event.c
arch/arm/kernel/reboot.c
arch/arm/kernel/smp.c
arch/arm/kernel/vdso.c
arch/arm/lib/memcpy.S
arch/arm/lib/memset.S
arch/arm/lib/uaccess_with_memcpy.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-imx/gpc.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/dma.c
arch/arm/mach-omap2/omap-wakeupgen.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-prima2/Kconfig
arch/arm/mach-prima2/rtciobrg.c
arch/arm/mach-pxa/capc7117.c
arch/arm/mach-pxa/cm-x2xx.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/colibri-pxa270.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/icontrol.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/vpac270.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-spear/generic.h
arch/arm/mach-spear/include/mach/irqs.h
arch/arm/mach-spear/include/mach/misc_regs.h
arch/arm/mach-spear/include/mach/spear.h
arch/arm/mach-spear/include/mach/uncompress.h
arch/arm/mach-spear/pl080.c
arch/arm/mach-spear/pl080.h
arch/arm/mach-spear/restart.c
arch/arm/mach-spear/spear1310.c
arch/arm/mach-spear/spear1340.c
arch/arm/mach-spear/spear13xx.c
arch/arm/mach-spear/spear300.c
arch/arm/mach-spear/spear310.c
arch/arm/mach-spear/spear320.c
arch/arm/mach-spear/spear3xx.c
arch/arm/mach-sunxi/Kconfig
arch/arm/mach-sunxi/sunxi.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-v7.S
arch/arm/net/bpf_jit_32.c
arch/arm/vdso/Makefile
arch/arm/vdso/vdsomunge.c
arch/arm64/Kconfig
arch/arm64/boot/dts/apm/apm-mustang.dts
arch/arm64/boot/dts/apm/apm-storm.dtsi
arch/arm64/boot/dts/arm/Makefile
arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts [new file with mode: 0644]
arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
arch/arm64/configs/defconfig
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/mm-arch-hooks.h [deleted file]
arch/arm64/kernel/efi.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/entry32.S
arch/arm64/kernel/irq.c
arch/arm64/kernel/signal32.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/vdso.c
arch/arm64/mm/Makefile
arch/avr32/include/asm/Kbuild
arch/avr32/include/asm/mm-arch-hooks.h [deleted file]
arch/avr32/kernel/time.c
arch/avr32/mach-at32ap/clock.c
arch/blackfin/include/asm/Kbuild
arch/blackfin/include/asm/mm-arch-hooks.h [deleted file]
arch/c6x/include/asm/Kbuild
arch/c6x/include/asm/mm-arch-hooks.h [deleted file]
arch/cris/arch-v32/drivers/sync_serial.c
arch/cris/include/asm/Kbuild
arch/cris/include/asm/mm-arch-hooks.h [deleted file]
arch/frv/include/asm/Kbuild
arch/frv/include/asm/mm-arch-hooks.h [deleted file]
arch/h8300/include/asm/Kbuild
arch/hexagon/include/asm/Kbuild
arch/hexagon/include/asm/mm-arch-hooks.h [deleted file]
arch/ia64/include/asm/Kbuild
arch/ia64/include/asm/mm-arch-hooks.h [deleted file]
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/io.h
arch/m32r/include/asm/mm-arch-hooks.h [deleted file]
arch/m68k/Kconfig.cpu
arch/m68k/configs/m5208evb_defconfig
arch/m68k/configs/m5249evb_defconfig
arch/m68k/configs/m5272c3_defconfig
arch/m68k/configs/m5275evb_defconfig
arch/m68k/configs/m5307c3_defconfig
arch/m68k/configs/m5407c3_defconfig
arch/m68k/configs/m5475evb_defconfig
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/coldfire.h
arch/m68k/include/asm/io_mm.h
arch/m68k/include/asm/mm-arch-hooks.h [deleted file]
arch/metag/include/asm/Kbuild
arch/metag/include/asm/mm-arch-hooks.h [deleted file]
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/mm-arch-hooks.h [deleted file]
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/ath79/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/include/asm/Kbuild
arch/mips/include/asm/fpu.h
arch/mips/include/asm/mach-bcm63xx/dma-coherence.h [deleted file]
arch/mips/include/asm/mach-loongson64/mmzone.h
arch/mips/include/asm/mach-sibyte/war.h
arch/mips/include/asm/mm-arch-hooks.h [deleted file]
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/stackframe.h
arch/mips/include/uapi/asm/sigcontext.h
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/branch.c
arch/mips/kernel/cps-vec.S
arch/mips/kernel/genex.S
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/prom.c
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/signal32.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/lantiq/irq.c
arch/mips/loongson64/common/bonito-irq.c
arch/mips/loongson64/common/cmdline.c
arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c
arch/mips/loongson64/common/env.c
arch/mips/loongson64/common/irq.c
arch/mips/loongson64/common/setup.c
arch/mips/loongson64/fuloong-2e/irq.c
arch/mips/loongson64/lemote-2f/clock.c
arch/mips/loongson64/loongson-3/numa.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/math-emu/cp1emu.c
arch/mips/mm/c-r4k.c
arch/mips/mm/cache.c
arch/mips/mm/fault.c
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-time.c
arch/mips/mti-sead3/sead3-time.c
arch/mips/netlogic/common/smp.c
arch/mips/paravirt/paravirt-smp.c
arch/mips/pistachio/init.c
arch/mips/pistachio/time.c
arch/mips/pmcs-msp71xx/msp_smp.c
arch/mips/ralink/irq.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sibyte/Kconfig
arch/mips/sibyte/bcm1480/smp.c
arch/mips/sibyte/common/bus_watcher.c
arch/mips/sibyte/sb1250/setup.c
arch/mips/sibyte/sb1250/smp.c
arch/mn10300/include/asm/Kbuild
arch/mn10300/include/asm/mm-arch-hooks.h [deleted file]
arch/nios2/include/asm/Kbuild
arch/nios2/include/asm/mm-arch-hooks.h [deleted file]
arch/openrisc/Kconfig
arch/openrisc/include/asm/Kbuild
arch/openrisc/include/asm/mm-arch-hooks.h [deleted file]
arch/parisc/include/asm/Kbuild
arch/parisc/include/asm/mm-arch-hooks.h [deleted file]
arch/parisc/include/asm/pgalloc.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/tlbflush.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/traps.c
arch/powerpc/include/asm/mpc52xx_psc.h
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/traps.c
arch/powerpc/mm/fault.c
arch/powerpc/perf/hv-24x7.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/opal-elog.c
arch/powerpc/platforms/powernv/opal-prd.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/sysdev/ppc4xx_hsta_msi.c
arch/s390/include/asm/Kbuild
arch/s390/include/asm/ctl_reg.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/mm-arch-hooks.h [deleted file]
arch/s390/include/asm/page.h
arch/s390/include/asm/perf_event.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/cache.c
arch/s390/kernel/entry.S
arch/s390/kernel/nmi.c
arch/s390/kernel/process.c
arch/s390/kernel/sclp.S
arch/s390/kernel/setup.c
arch/s390/kernel/traps.c
arch/s390/kvm/kvm-s390.c
arch/s390/mm/pgtable.c
arch/s390/net/bpf_jit_comp.c
arch/s390/oprofile/init.c
arch/score/include/asm/Kbuild
arch/score/include/asm/mm-arch-hooks.h [deleted file]
arch/sh/include/asm/Kbuild
arch/sh/include/asm/mm-arch-hooks.h [deleted file]
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/mm-arch-hooks.h [deleted file]
arch/sparc/include/asm/visasm.h
arch/sparc/lib/NG4memcpy.S
arch/sparc/lib/VISsave.S
arch/sparc/lib/ksyms.c
arch/tile/include/asm/Kbuild
arch/tile/include/asm/mm-arch-hooks.h [deleted file]
arch/tile/kernel/compat_signal.c
arch/tile/kernel/setup.c
arch/tile/lib/memcpy_user_64.c
arch/um/include/asm/Kbuild
arch/um/include/asm/mm-arch-hooks.h [deleted file]
arch/unicore32/include/asm/Kbuild
arch/unicore32/include/asm/mm-arch-hooks.h [deleted file]
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/boot/compressed/eboot.c
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/Kbuild
arch/x86/include/asm/desc.h
arch/x86/include/asm/espfix.h
arch/x86/include/asm/fpu/types.h
arch/x86/include/asm/intel_pmc_ipc.h
arch/x86/include/asm/kasan.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mm-arch-hooks.h [deleted file]
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/sigcontext.h
arch/x86/include/asm/switch_to.h
arch/x86/include/uapi/asm/hyperv.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/include/uapi/asm/sigcontext.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_cqm.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/espfix_64.c
arch/x86/kernel/fpu/core.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_64.S
arch/x86/kernel/irq.c
arch/x86/kernel/ldt.c
arch/x86/kernel/nmi.c
arch/x86/kernel/process.c
arch/x86/kernel/process_64.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/step.c
arch/x86/kernel/tsc.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/iommu.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/mtrr.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/lib/usercopy.c
arch/x86/math-emu/fpu_entry.c
arch/x86/math-emu/fpu_system.h
arch/x86/math-emu/get_address.c
arch/x86/mm/ioremap.c
arch/x86/mm/kasan_init_64.c
arch/x86/mm/mmap.c
arch/x86/mm/mpx.c
arch/x86/mm/tlb.c
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi.c
arch/x86/power/cpu.c
arch/x86/xen/Kconfig
arch/x86/xen/Makefile
arch/x86/xen/enlighten.c
arch/x86/xen/xen-ops.h
arch/xtensa/include/asm/Kbuild
arch/xtensa/include/asm/mm-arch-hooks.h [deleted file]
block/bio-integrity.c
block/bio.c
block/blk-cgroup.c
block/blk-core.c
block/blk-mq.c
block/blk-settings.c
crypto/authencesn.c
drivers/acpi/acpi_lpss.c
drivers/acpi/device_pm.c
drivers/acpi/nfit.c
drivers/acpi/nfit.h
drivers/acpi/osl.c
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/ahci_brcmstb.c
drivers/ata/ahci_platform.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/libata-transport.c
drivers/ata/libata.h
drivers/ata/pata_arasan_cf.c
drivers/ata/sata_sx4.c
drivers/base/firmware_class.c
drivers/base/power/domain.c
drivers/base/power/wakeirq.c
drivers/base/power/wakeup.c
drivers/base/regmap/regcache-rbtree.c
drivers/block/null_blk.c
drivers/block/nvme-core.c
drivers/block/rbd.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btbcm.c
drivers/char/hw_random/core.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm_crb.c
drivers/clk/at91/clk-h32mx.c
drivers/clk/at91/clk-main.c
drivers/clk/at91/clk-master.c
drivers/clk/at91/clk-pll.c
drivers/clk/at91/clk-system.c
drivers/clk/at91/clk-utmi.c
drivers/clk/bcm/clk-iproc-asiu.c
drivers/clk/bcm/clk-iproc-pll.c
drivers/clk/clk-stm32f4.c
drivers/clk/mediatek/clk-mt8173.c
drivers/clk/pxa/clk-pxa3xx.c
drivers/clk/qcom/clk-rcg2.c
drivers/clk/spear/clk-aux-synth.c
drivers/clk/spear/clk-frac-synth.c
drivers/clk/spear/clk-gpt-synth.c
drivers/clk/spear/clk-vco-pll.c
drivers/clk/spear/clk.c
drivers/clk/spear/clk.h
drivers/clk/spear/spear1310_clock.c
drivers/clk/spear/spear1340_clock.c
drivers/clk/spear/spear3xx_clock.c
drivers/clk/spear/spear6xx_clock.c
drivers/clk/st/clk-flexgen.c
drivers/clk/st/clkgen-fsyn.c
drivers/clk/st/clkgen-mux.c
drivers/clk/st/clkgen-pll.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/timer-imx-gpt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/freq_table.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpuidle/cpuidle.c
drivers/crypto/caam/caamhash.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/nx/nx-aes-ccm.c
drivers/crypto/nx/nx-aes-ctr.c
drivers/crypto/nx/nx-aes-gcm.c
drivers/crypto/nx/nx-aes-xcbc.c
drivers/crypto/nx/nx-sha256.c
drivers/crypto/nx/nx-sha512.c
drivers/crypto/nx/nx.c
drivers/crypto/nx/nx.h
drivers/crypto/omap-des.c
drivers/crypto/qat/qat_common/qat_algs.c
drivers/dma/at_hdmac.c
drivers/dma/at_hdmac_regs.h
drivers/dma/at_xdmac.c
drivers/dma/dmaengine.c
drivers/dma/dw/core.c
drivers/dma/mv_xor.c
drivers/dma/pl330.c
drivers/dma/virt-dma.c
drivers/dma/virt-dma.h
drivers/dma/xgene-dma.c
drivers/edac/ppc4xx_edac.c
drivers/extcon/extcon-palmas.c
drivers/extcon/extcon.c
drivers/firmware/broadcom/bcm47xx_nvram.c
drivers/firmware/efi/cper.c
drivers/firmware/efi/efi.c
drivers/gpio/gpio-brcmstb.c
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-max732x.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-xilinx.c
drivers/gpio/gpio-zynq.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/cz_dpm.c
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/armada/armada_crtc.c
drivers/gpu/drm/armada/armada_gem.c
drivers/gpu/drm/armada/armada_overlay.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_dmabuf.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/i915/i915_ioc32.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/intel_atomic.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/imx/imx-tve.c
drivers/gpu/drm/imx/parallel-display.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_prime.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_platform.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nv04_fbcon.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nvc0_fbcon.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_fbdev.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/omapdrm/omap_plane.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/radeon_audio.c
drivers/gpu/drm/radeon/radeon_audio.h
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/ipu-v3/ipu-common.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-uclogic.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hwmon/dell-smm-hwmon.c
drivers/hwmon/g762.c
drivers/hwmon/nct7802.c
drivers/hwmon/nct7904.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-jz4780.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-xgene-slimpro.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-slave-eeprom.c
drivers/iio/accel/bmc150-accel.c
drivers/iio/accel/mma8452.c
drivers/iio/adc/Kconfig
drivers/iio/adc/at91_adc.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/twl4030-madc.c
drivers/iio/adc/vf610_adc.c
drivers/iio/common/hid-sensors/hid-sensor-trigger.c
drivers/iio/dac/ad5624r_spi.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/light/Kconfig
drivers/iio/light/cm3323.c
drivers/iio/light/ltr501.c
drivers/iio/light/stk3310.c
drivers/iio/light/tcs3414.c
drivers/iio/magnetometer/Kconfig
drivers/iio/magnetometer/bmc150_magn.c
drivers/iio/magnetometer/mmc35240.c
drivers/iio/proximity/sx9500.c
drivers/iio/temperature/mlx90614.c
drivers/iio/temperature/tmp006.c
drivers/infiniband/core/agent.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/iwpm_msg.c
drivers/infiniband/core/iwpm_util.c
drivers/infiniband/core/iwpm_util.h
drivers/infiniband/core/mad.c
drivers/infiniband/core/multicast.c
drivers/infiniband/core/opa_smi.h
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/smi.c
drivers/infiniband/core/smi.h
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucm.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/ehca/ehca_sqp.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_mad.c
drivers/infiniband/hw/ipath/ipath_verbs.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx5/mad.c
drivers/infiniband/hw/mthca/mthca_mad.c
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_abi.h
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_ah.h
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
drivers/infiniband/hw/ocrdma/ocrdma_hw.h
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_sli.h
drivers/infiniband/hw/ocrdma/ocrdma_stats.c
drivers/infiniband/hw/ocrdma/ocrdma_stats.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
drivers/infiniband/hw/qib/qib_mad.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/input-leds.c
drivers/input/joystick/turbografx.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/misc/axp20x-pek.c
drivers/input/misc/twl4030-vibra.c
drivers/input/mouse/alps.c
drivers/input/mouse/bcm5974.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_v2.c
drivers/iommu/arm-smmu-v3.c
drivers/iommu/intel-iommu.c
drivers/irqchip/irq-crossbar.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-mips-gic.c
drivers/irqchip/spear-shirq.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/macintosh/ans-lcd.c
drivers/md/Kconfig
drivers/md/bcache/closure.h
drivers/md/bcache/io.c
drivers/md/bcache/journal.c
drivers/md/bcache/request.c
drivers/md/bitmap.c
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-policy-smq.c
drivers/md/dm-cache-target.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/md-cluster.c
drivers/md/md-cluster.h
drivers/md/md.c
drivers/md/persistent-data/dm-btree-internal.h
drivers/md/persistent-data/dm-btree-remove.c
drivers/md/persistent-data/dm-btree-spine.c
drivers/md/persistent-data/dm-btree.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/dvb-frontends/Kconfig
drivers/media/pci/cobalt/Kconfig
drivers/media/pci/cobalt/cobalt-irq.c
drivers/media/pci/ivtv/ivtvfb.c
drivers/media/pci/mantis/mantis_dma.c
drivers/media/rc/ir-rc5-decoder.c
drivers/media/rc/ir-rc6-decoder.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/nuvoton-cir.h
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-ir-raw.c
drivers/media/rc/rc-loopback.c
drivers/media/rc/rc-main.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/memory/omap-gpmc.c
drivers/mfd/Kconfig
drivers/mfd/arizona-core.c
drivers/mfd/stmpe-i2c.c
drivers/mfd/stmpe-spi.c
drivers/misc/cxl/api.c
drivers/misc/cxl/context.c
drivers/misc/cxl/main.c
drivers/misc/cxl/pci.c
drivers/misc/cxl/vphb.c
drivers/misc/eeprom/at24.c
drivers/misc/mei/bus.c
drivers/misc/mei/init.c
drivers/misc/mei/main.c
drivers/misc/mei/nfc.c
drivers/misc/mic/scif/scif_nodeqp.c
drivers/mmc/card/block.c
drivers/mmc/host/Kconfig
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci.c
drivers/net/bonding/bond_main.c
drivers/net/can/at91_can.c
drivers/net/can/bfin_can.c
drivers/net/can/c_can/c_can.c
drivers/net/can/cc770/cc770.c
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/grcan.c
drivers/net/can/rcar_can.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/slcan.c
drivers/net/can/spi/mcp251x.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/can/usb/usb_8dev.c
drivers/net/can/vcan.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/amd/xgbe/xgbe-desc.c
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cavium/Kconfig
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h
drivers/net/ethernet/cavium/thunder/thunder_bgx.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/fs_enet/mac-fec.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/micrel/ks8842.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/rocker/rocker.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef10_sriov.c
drivers/net/ethernet/sfc/ef10_sriov.h
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/netcp.h
drivers/net/ethernet/ti/netcp_core.c
drivers/net/ethernet/ti/netcp_ethss.c
drivers/net/ethernet/ti/netcp_sgmii.c
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/hamradio/bpqether.c
drivers/net/hamradio/mkiss.c
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/macvtap.c
drivers/net/ntb_netdev.c
drivers/net/phy/Kconfig
drivers/net/phy/dp83867.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/phy/smsc.c
drivers/net/ppp/ppp_generic.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/huawei_cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/wan/cosa.c
drivers/net/wan/z85230.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
drivers/net/wireless/rsi/rsi_91x_usb_ops.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/rtl8723be/sw.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/ntb/ntb.c
drivers/ntb/ntb_transport.c
drivers/nvdimm/bus.c
drivers/nvdimm/region_devs.c
drivers/of/Kconfig
drivers/of/unittest.c
drivers/parport/share.c
drivers/pci/Kconfig
drivers/pci/probe.c
drivers/phy/Kconfig
drivers/phy/phy-berlin-usb.c
drivers/phy/phy-sun4i-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/freescale/pinctrl-imx1-core.c
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/pinctrl-lpc18xx.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/pinctrl/spear/pinctrl-spear.c
drivers/pinctrl/spear/pinctrl-spear.h
drivers/pinctrl/spear/pinctrl-spear1310.c
drivers/pinctrl/spear/pinctrl-spear1340.c
drivers/pinctrl/spear/pinctrl-spear300.c
drivers/pinctrl/spear/pinctrl-spear310.c
drivers/pinctrl/spear/pinctrl-spear320.c
drivers/pinctrl/spear/pinctrl-spear3xx.c
drivers/pinctrl/spear/pinctrl-spear3xx.h
drivers/platform/chrome/Kconfig
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/intel_pmc_ipc.c
drivers/platform/x86/intel_scu_ipc.c
drivers/pnp/system.c
drivers/regulator/88pm800.c
drivers/regulator/core.c
drivers/regulator/max8973-regulator.c
drivers/regulator/s2mps11.c
drivers/rtc/rtc-armada38x.c
drivers/rtc/rtc-mt6397.c
drivers/s390/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd_alias.c
drivers/s390/char/sclp_early.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/kvm/Makefile [deleted file]
drivers/s390/kvm/kvm_virtio.c [deleted file]
drivers/s390/kvm/virtio_ccw.c [deleted file]
drivers/s390/virtio/Makefile [new file with mode: 0644]
drivers/s390/virtio/kvm_virtio.c [new file with mode: 0644]
drivers/s390/virtio/virtio_ccw.c [new file with mode: 0644]
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libiscsi.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_pm.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_srp.c
drivers/scsi/sd.c
drivers/scsi/st.c
drivers/scsi/virtio_scsi.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-atmel.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm63xx-hsspi.c
drivers/spi/spi-bitbang-txrx.h
drivers/spi/spi-davinci.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.c
drivers/spi/spi-dw.h
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-fsl-lib.c
drivers/spi/spi-fsl-lib.h
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-img-spfi.c
drivers/spi/spi-imx.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-mt65xx.c [new file with mode: 0644]
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-orion.c
drivers/spi/spi-pxa2xx-pci.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-pxa2xx.h
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c24xx.c
drivers/spi/spi-xilinx.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/staging/board/Kconfig
drivers/staging/comedi/drivers/das1800.c
drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
drivers/staging/lustre/lustre/obdclass/debug.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6656/main_usb.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/target_core_configfs.c
drivers/target/target_core_hba.c
drivers/target/target_core_pr.c
drivers/target/target_core_rd.c
drivers/target/target_core_spc.c
drivers/thermal/cpu_cooling.c
drivers/thermal/hisi_thermal.c
drivers/thermal/power_allocator.c
drivers/thermal/samsung/Kconfig
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
drivers/tty/n_tty.c
drivers/tty/serial/Kconfig
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/etraxfs-uart.c
drivers/tty/serial/imx.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/vt/selection.c
drivers/tty/vt/vt.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/chipidea/host.h
drivers/usb/class/cdc-acm.c
drivers/usb/common/ulpi.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/usb.h
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/hcd_queue.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/ep0.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/f_printer.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/udc/bdc/bdc_ep.c
drivers/usb/gadget/udc/fotg210-udc.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/udc-core.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-tmio.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/musb_virthub.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/sierra.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/unusual_devs.h
drivers/vfio/vfio.c
drivers/vhost/vhost.c
drivers/video/console/fbcon.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/omap2/dss/dss-of.c
drivers/video/fbdev/pxa3xx-gcu.c
drivers/video/fbdev/stifb.c
drivers/video/of_videomode.c
drivers/virtio/virtio_input.c
drivers/watchdog/sp805_wdt.c
drivers/xen/balloon.c
drivers/xen/gntdev.c
drivers/xen/xenbus/xenbus_client.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.h
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/qgroup.c
fs/btrfs/relocation.c
fs/btrfs/scrub.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/locks.c
fs/ceph/super.h
fs/compat_ioctl.c
fs/configfs/item.c
fs/dax.c
fs/dcache.c
fs/ecryptfs/file.c
fs/ext4/extents.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/f2fs/data.c
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/segment.c
fs/file_table.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/hpfs/alloc.c
fs/hpfs/dir.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/super.c
fs/hugetlbfs/inode.c
fs/jfs/file.c
fs/jfs/inode.c
fs/jfs/ioctl.c
fs/jfs/namei.c
fs/locks.c
fs/namei.c
fs/namespace.c
fs/nfs/client.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs42proc.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/write.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nilfs2/ioctl.c
fs/notify/mark.c
fs/ocfs2/aops.c
fs/ocfs2/dlmglue.c
fs/ocfs2/ioctl.c
fs/overlayfs/inode.c
fs/pnode.h
fs/proc/Kconfig
fs/proc/base.c
fs/proc/kcore.c
fs/signalfd.c
fs/udf/inode.c
fs/xfs/libxfs/xfs_attr_remote.c
fs/xfs/xfs_file.c
fs/xfs/xfs_log_recover.c
include/asm-generic/mm-arch-hooks.h [new file with mode: 0644]
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_edid.h
include/drm/drm_pciids.h
include/linux/acpi.h
include/linux/amba/sp810.h
include/linux/ata.h
include/linux/blk-cgroup.h
include/linux/buffer_head.h
include/linux/can/skb.h
include/linux/ceph/messenger.h
include/linux/clkdev.h
include/linux/compat.h
include/linux/compiler.h
include/linux/configfs.h
include/linux/cper.h
include/linux/cpu.h
include/linux/cpufreq.h
include/linux/dcache.h
include/linux/device.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/gpio/driver.h
include/linux/hid-sensor-hub.h
include/linux/hugetlb.h
include/linux/init.h
include/linux/iommu.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/kernel.h
include/linux/kobject.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmiotrace.h
include/linux/mod_devicetable.h
include/linux/module.h
include/linux/mtd/nand.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/of_device.h
include/linux/page-flags.h
include/linux/page_owner.h
include/linux/pata_arasan_cf_data.h
include/linux/platform_data/macb.h
include/linux/platform_data/mmc-esdhc-imx.h
include/linux/platform_data/spi-davinci.h
include/linux/platform_data/spi-mt65xx.h [new file with mode: 0644]
include/linux/printk.h
include/linux/pxa2xx_ssp.h
include/linux/rtc/sirfsoc_rtciobrg.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/tick.h
include/linux/timekeeping.h
include/linux/usb/cdc_ncm.h
include/media/rc-core.h
include/media/videobuf2-core.h
include/net/act_api.h
include/net/cfg80211.h
include/net/inet_frag.h
include/net/ip.h
include/net/ip_fib.h
include/net/netfilter/nf_conntrack.h
include/net/netns/conntrack.h
include/net/sock.h
include/rdma/ib_verbs.h
include/scsi/scsi_eh.h
include/scsi/scsi_transport_srp.h
include/sound/soc-topology.h
include/target/iscsi/iscsi_target_core.h
include/uapi/drm/amdgpu_drm.h
include/uapi/drm/i915_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/linux/netconf.h
include/uapi/linux/pci_regs.h
include/uapi/linux/virtio_net.h
include/uapi/linux/virtio_pci.h
include/uapi/linux/virtio_ring.h
include/uapi/sound/asoc.h
init/main.c
ipc/mqueue.c
ipc/sem.c
ipc/shm.c
kernel/auditsc.c
kernel/cpu.c
kernel/cpuset.c
kernel/events/core.c
kernel/events/internal.h
kernel/events/ring_buffer.c
kernel/fork.c
kernel/irq/chip.c
kernel/irq/internals.h
kernel/irq/resend.c
kernel/kthread.c
kernel/locking/qspinlock_paravirt.h
kernel/module.c
kernel/resource.c
kernel/sched/fair.c
kernel/signal.c
kernel/time/clockevents.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-sched.h
kernel/time/timer.c
kernel/trace/ftrace.c
kernel/trace/trace.h
kernel/trace/trace_branch.c
lib/Kconfig.kasan
lib/decompress.c
lib/dma-debug.c
lib/hexdump.c
lib/iommu-common.c
lib/kobject.c
lib/rhashtable.c
mm/cma.h
mm/cma_debug.c
mm/huge_memory.c
mm/kasan/kasan.c
mm/kasan/report.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/migrate.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_owner.c
mm/shmem.c
mm/slab.c
mm/slab_common.c
mm/slub.c
mm/vmscan.c
net/9p/client.c
net/9p/trans_virtio.c
net/ax25/ax25_subr.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/gateway_client.c
net/batman-adv/soft-interface.c
net/batman-adv/translation-table.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/bridge/br_forward.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netfilter_hooks.c
net/bridge/br_netfilter_ipv6.c
net/bridge/br_netlink.c
net/bridge/br_stp.c
net/bridge/br_stp_if.c
net/bridge/br_stp_timer.c
net/caif/caif_socket.c
net/can/af_can.c
net/can/bcm.c
net/can/raw.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/core/datagram.c
net/core/dev.c
net/core/dst.c
net/core/gen_estimator.c
net/core/netclassid_cgroup.c
net/core/pktgen.c
net/core/request_sock.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/proto.c
net/dsa/dsa.c
net/dsa/slave.c
net/ieee802154/6lowpan/reassembly.c
net/ipv4/arp.c
net/ipv4/datagram.c
net/ipv4/devinet.c
net/ipv4/fib_lookup.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/inet_fragment.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_fragment.c
net/ipv4/ip_tunnel.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/datagram.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_input.c
net/ipv6/ip6_offload.c
net/ipv6/mcast_snoop.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6t_SYNPROXY.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/llc/af_llc.c
net/mac80211/debugfs_netdev.c
net/mac80211/iface.c
net/mac80211/mesh_plink.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/tdls.c
net/mac80211/tx.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_sched.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_queue.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nfnetlink.c
net/netfilter/xt_CT.c
net/netfilter/xt_IDLETIMER.c
net/netlink/af_netlink.c
net/openvswitch/actions.c
net/openvswitch/flow_table.c
net/packet/af_packet.c
net/rds/ib_rdma.c
net/rds/info.c
net/rds/transport.c
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_mirred.c
net/sched/act_pedit.c
net/sched/cls_bpf.c
net/sched/cls_flow.c
net/sched/cls_flower.c
net/sched/sch_choke.c
net/sched/sch_fq_codel.c
net/sched/sch_plug.c
net/sched/sch_sfq.c
net/sctp/socket.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/clnt.c
net/sunrpc/xprtsock.c
net/switchdev/switchdev.c
net/tipc/socket.c
net/wireless/chan.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/trace.h
samples/trace_events/trace-events-sample.h
scripts/checkpatch.pl
scripts/kconfig/streamline_config.pl
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
scripts/mod/modpost.c
security/keys/keyring.c
security/selinux/hooks.c
security/selinux/ss/ebitmap.c
security/yama/yama_lsm.c
sound/core/pcm_native.c
sound/firewire/amdtp.c
sound/firewire/amdtp.h
sound/firewire/fireworks/fireworks.c
sound/firewire/fireworks/fireworks.h
sound/firewire/fireworks/fireworks_stream.c
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_stream.c
sound/hda/hdac_i915.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/oxygen/oxygen_mixer.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/codecs/cs4265.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/ssm4567.c
sound/soc/fsl/fsl_ssi.c
sound/soc/intel/Makefile
sound/soc/intel/atom/sst/sst_drv_interface.c
sound/soc/intel/baytrail/sst-baytrail-ipc.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/haswell/sst-haswell-ipc.c
sound/soc/mediatek/mt8173-max98090.c
sound/soc/mediatek/mt8173-rt5650-rt5676.c
sound/soc/mediatek/mtk-afe-pcm.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-topology.c
sound/soc/zte/zx296702-i2s.c
sound/soc/zte/zx296702-spdif.c
sound/sparc/amd7930.c
sound/usb/card.c
sound/usb/line6/pcm.c
sound/usb/mixer_maps.c
sound/usb/quirks-table.h
tools/include/linux/compiler.h
tools/include/linux/export.h [deleted file]
tools/include/linux/rbtree.h [new file with mode: 0644]
tools/include/linux/rbtree_augmented.h [new file with mode: 0644]
tools/lib/api/Makefile
tools/lib/hweight.c [new file with mode: 0644]
tools/lib/rbtree.c [new file with mode: 0644]
tools/lib/traceevent/Makefile
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/builtin-record.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/config/Makefile
tools/perf/ui/browsers/hists.c
tools/perf/util/Build
tools/perf/util/auxtrace.c
tools/perf/util/include/linux/rbtree.h [deleted file]
tools/perf/util/include/linux/rbtree_augmented.h [deleted file]
tools/perf/util/machine.c
tools/perf/util/python-ext-sources
tools/perf/util/stat-shadow.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread_map.c
tools/perf/util/vdso.c
tools/testing/nvdimm/Kbuild
tools/testing/nvdimm/test/iomap.c
tools/testing/nvdimm/test/nfit.c
tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
virt/kvm/vfio.c

diff --git a/.get_maintainer.ignore b/.get_maintainer.ignore
new file mode 100644 (file)
index 0000000..cca6d87
--- /dev/null
@@ -0,0 +1 @@
+Christoph Hellwig <hch@lst.de>
index 977f958eedbe6a6e56f63033b17c3cb66cd8b8a3..4b31af54ccd5864359c0810f9733f3026181a631 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -17,6 +17,7 @@ Aleksey Gorelov <aleksey_gorelov@phoenix.com>
 Al Viro <viro@ftp.linux.org.uk>
 Al Viro <viro@zenIV.linux.org.uk>
 Andreas Herrmann <aherrman@de.ibm.com>
+Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
 Andrew Morton <akpm@linux-foundation.org>
 Andrew Vasquez <andrew.vasquez@qlogic.com>
 Andy Adamson <andros@citi.umich.edu>
@@ -116,6 +117,7 @@ Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
 Simon Kelley <simon@thekelleys.org.uk>
 Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
 Stephen Hemminger <shemminger@osdl.org>
+Sudeep Holla <sudeep.holla@arm.com> Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
 Sumit Semwal <sumit.semwal@ti.com>
 Tejun Heo <htejun@gmail.com>
 Thomas Graf <tgraf@suug.ch>
@@ -125,7 +127,9 @@ Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
 Uwe Kleine-König <ukl@pengutronix.de>
 Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
 Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
-Viresh Kumar <viresh.linux@gmail.com> <viresh.kumar@st.com>
+Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
+Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
+Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
 Takashi YOSHII <takashi.yoshii.zj@renesas.com>
 Yusuke Goda <goda.yusuke@renesas.com>
 Gustavo Padovan <gustavo@las.ic.unicamp.br>
index bbed111c31b4ed7658e61ac6b7140284c3035dc6..70c9b1ac66dbc5880c90312b47ba0b28669a77a6 100644 (file)
@@ -1234,10 +1234,8 @@ Description:
                object is near the sensor, usually be observing
                reflectivity of infrared or ultrasound emitted.
                Often these sensors are unit less and as such conversion
-               to SI units is not possible.  Where it is, the units should
-               be meters.  If such a conversion is not possible, the reported
-               values should behave in the same way as a distance, i.e. lower
-               values indicate something is closer to the sensor.
+               to SI units is not possible. Higher proximity measurements
+               indicate closer objects, and vice versa.
 
 What:          /sys/.../iio:deviceX/in_illuminance_input
 What:          /sys/.../iio:deviceX/in_illuminance_raw
index c0312cbd023d249e0bb34ab1b2970b5036f3ef30..2fb9a5457522a48cf590f88d14463dfafefb668a 100644 (file)
@@ -3383,7 +3383,7 @@ void intel_crt_init(struct drm_device *dev)
        <td valign="top" >TBD</td>
        </tr>
        <tr>
-       <td rowspan="2" valign="top" >omap</td>
+       <td valign="top" >omap</td>
        <td valign="top" >Generic</td>
        <td valign="top" >“zorder”</td>
        <td valign="top" >RANGE</td>
index 65610bf52ebffbad7e13d8f522df603487ef59e2..1b049be6c84f0e4bddfb2dbf212edf71ce91be4e 100644 (file)
@@ -60,4 +60,4 @@ Introduction
   Document Author
   ---------------
 
-  Viresh Kumar <viresh.linux@gmail.com>, (c) 2010-2012 ST Microelectronics
+  Viresh Kumar <vireshk@kernel.org>, (c) 2010-2012 ST Microelectronics
index 1fe2d7fd4108ffd98f0585b23e04f36e40c1cd57..5e38e1582f9545a6c82d0252baa4841e91a577d3 100644 (file)
@@ -36,7 +36,7 @@ SunXi family
         + User Manual
           http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
 
-      - Allwinner A23
+      - Allwinner A23 (sun8i)
         + Datasheet
           http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf
         + User Manual
@@ -55,7 +55,23 @@ SunXi family
         + User Manual
           http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf
 
+      - Allwinner A33 (sun8i)
+        + Datasheet
+          http://dl.linux-sunxi.org/A33/A33%20Datasheet%20release%201.1.pdf
+        + User Manual
+          http://dl.linux-sunxi.org/A33/A33%20user%20manual%20release%201.1.pdf
+
+      - Allwinner H3 (sun8i)
+        + Datasheet
+          http://dl.linux-sunxi.org/H3/Allwinner_H3_Datasheet_V1.0.pdf
+
     * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs
       - Allwinner A80
         + Datasheet
          http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf
+
+    * Octa ARM Cortex-A7 based SoCs
+      - Allwinner A83T
+        + Not Supported
+        + Datasheet
+          http://dl.linux-sunxi.org/A83T/A83T_datasheet_Revision_1.1.pdf
index 82960cffbad346d73a8e47ebd188a54a9db4e4c1..785eab87aa71dc68aceeb970676a614c9c2c6381 100644 (file)
@@ -258,6 +258,12 @@ cache metadata mode      : ro if read-only, rw if read-write
        no further I/O will be permitted and the status will just
        contain the string 'Fail'.  The userspace recovery tools
        should then be used.
+needs_check             : 'needs_check' if set, '-' if not set
+       A metadata operation has failed, resulting in the needs_check
+       flag being set in the metadata's superblock.  The metadata
+       device must be deactivated and checked/repaired before the
+       cache can be made fully operational again.  '-' indicates
+       needs_check is not set.
 
 Messages
 --------
index 4f67578b295483bcc14d48f069c6ded3581e3f94..1699a55b7b709adddd18b97cd769cb8946662e48 100644 (file)
@@ -296,7 +296,7 @@ ii) Status
        underlying device.  When this is enabled when loading the table,
        it can get disabled if the underlying device doesn't support it.
 
-    ro|rw
+    ro|rw|out_of_data_space
        If the pool encounters certain types of device failures it will
        drop into a read-only metadata mode in which no changes to
        the pool metadata (like allocating new blocks) are permitted.
@@ -314,6 +314,13 @@ ii) Status
        module parameter can be used to change this timeout -- it
        defaults to 60 seconds but may be disabled using a value of 0.
 
+    needs_check
+       A metadata operation has failed, resulting in the needs_check
+       flag being set in the metadata's superblock.  The metadata
+       device must be deactivated and checked/repaired before the
+       thin-pool can be made fully operational again.  '-' indicates
+       needs_check is not set.
+
 iii) Messages
 
     create_thin <dev id>
index d6b794cef0b8b9907ab5a055a6502180b4350148..91e6e5c478d006245c5a88e7ae7e304d6fa7f097 100644 (file)
@@ -199,6 +199,7 @@ nodes to be present and contain the properties described below.
                            "qcom,kpss-acc-v1"
                            "qcom,kpss-acc-v2"
                            "rockchip,rk3066-smp"
+                           "ste,dbx500-smp"
 
        - cpu-release-addr
                Usage: required for systems that have an "enable-method"
index 42941fdefb11f163dcc18e7849297f099b76760e..67da20539540cc4e7725deac8748e70fcce357a5 100644 (file)
@@ -9,4 +9,6 @@ using one of the following compatible strings:
   allwinner,sun6i-a31
   allwinner,sun7i-a20
   allwinner,sun8i-a23
+  allwinner,sun8i-a33
+  allwinner,sun8i-h3
   allwinner,sun9i-a80
index d3058768b23de17e4c9916c2552b1266b9263d56..c53e0b08032fe73a42f130cd790b2b1dfa753939 100644 (file)
@@ -35,7 +35,7 @@ Example:
                        device_type = "dma";
                        reg = <0x0 0x1f270000 0x0 0x10000>,
                              <0x0 0x1f200000 0x0 0x10000>,
-                             <0x0 0x1b008000 0x0 0x2000>,
+                             <0x0 0x1b000000 0x0 0x400000>,
                              <0x0 0x1054a000 0x0 0x100>;
                        interrupts = <0x0 0x82 0x4>,
                                     <0x0 0xb8 0x4>,
index e75f0e549fff7cfe767786a83c57da5b5a4fe5b1..971c3eedb1c7b10de4d65134f8db5880fffd3462 100644 (file)
@@ -65,8 +65,10 @@ Optional properties:
 - edid: verbatim EDID data block describing attached display.
 - ddc: phandle describing the i2c bus handling the display data
   channel
-- port: A port node with endpoint definitions as defined in
+- port@[0-1]: Port nodes with endpoint definitions as defined in
   Documentation/devicetree/bindings/media/video-interfaces.txt.
+  Port 0 is the input port connected to the IPU display interface,
+  port 1 is the output port connected to a panel.
 
 example:
 
@@ -75,9 +77,29 @@ display@di0 {
        edid = [edid-data];
        interface-pix-fmt = "rgb24";
 
-       port {
+       port@0 {
+               reg = <0>;
+
                display_in: endpoint {
                        remote-endpoint = <&ipu_di0_disp0>;
                };
        };
+
+       port@1 {
+               reg = <1>;
+
+               display_out: endpoint {
+                       remote-endpoint = <&panel_in>;
+               };
+       };
+};
+
+panel {
+       ...
+
+       port {
+               panel_in: endpoint {
+                       remote-endpoint = <&display_out>;
+               };
+       };
 };
index c03eec1168721bdb1c851f7c42eba34ec48f4ba7..3443e0f838dfc8a53e548527a05cf9892f2c2a92 100644 (file)
@@ -35,3 +35,6 @@ the PCIe specification.
 
                       NOTE: this only applies to the SMMU itself, not
                       masters connected upstream of the SMMU.
+
+- hisilicon,broken-prefetch-cmd
+                    : Avoid sending CMD_PREFETCH_* commands to the SMMU.
index 938f8e1ba2051c98302705df219da917b7e5952f..0db60470ebb6aa7f8d236afd4599166dafb0c11b 100644 (file)
@@ -8,6 +8,7 @@ of the EMIF IP and memory parts attached to it.
 Required properties:
 - compatible   : Should be of the form "ti,emif-<ip-rev>" where <ip-rev>
   is the IP revision of the specific EMIF instance.
+                 For am437x should be ti,emif-am4372.
 
 - phy-type     : <u32> indicating the DDR phy type. Following are the
   allowed values
index 5d0376b8f2026ed57daabd33d684590d02ff5920..211e7785f4d240ec2ffc7258839f740e8b614b78 100644 (file)
@@ -17,7 +17,6 @@ Required properties:
               "fsl,imx6sx-usdhc"
 
 Optional properties:
-- fsl,cd-controller : Indicate to use controller internal card detection
 - fsl,wp-controller : Indicate to use controller internal write protection
 - fsl,delay-line : Specify the number of delay cells for override mode.
   This is used to set the clock delay for DLL(Delay Line) on override mode
@@ -35,7 +34,6 @@ esdhc@70004000 {
        compatible = "fsl,imx51-esdhc";
        reg = <0x70004000 0x4000>;
        interrupts = <1>;
-       fsl,cd-controller;
        fsl,wp-controller;
 };
 
index 305e3df3d9b1eb9a994c845eb28959275d2f20ed..9cf9446eaf2eac41d57251cb5853037e2b31e7c2 100644 (file)
@@ -82,6 +82,9 @@ Optional properties:
  - id: If there are multiple instance of the same type, in order to
    differentiate between each instance "id" can be used (e.g., multi-lane PCIe
    PHY). If "id" is not provided, it is set to default value of '1'.
+ - syscon-pllreset: Handle to system control region that contains the
+   CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0
+   register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy.
 
 This is usually a subnode of ocp2scp to which it is connected.
 
@@ -100,3 +103,16 @@ usb3phy@4a084400 {
                        "sysclk",
                        "refclk";
 };
+
+sata_phy: phy@4A096000 {
+       compatible = "ti,phy-pipe3-sata";
+       reg = <0x4A096000 0x80>, /* phy_rx */
+             <0x4A096400 0x64>, /* phy_tx */
+             <0x4A096800 0x40>; /* pll_ctrl */
+       reg-names = "phy_rx", "phy_tx", "pll_ctrl";
+       ctrl-module = <&omap_control_sata>;
+       clocks = <&sys_clkin1>, <&sata_ref_clk>;
+       clock-names = "sysclk", "refclk";
+       syscon-pllreset = <&scm_conf 0x3fc>;
+       #phy-cells = <0>;
+};
index 8832e8798912b5047f6a4250417b5923cbaf2a07..647817527c88f682b8ec939514334074f097b172 100644 (file)
@@ -6,14 +6,14 @@ PSC in UART mode
 For PSC in UART mode the needed PSC serial devices
 are specified by fsl,mpc5121-psc-uart nodes in the
 fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
-Controller node fsl,mpc5121-psc-fifo is requered there:
+Controller node fsl,mpc5121-psc-fifo is required there:
 
-fsl,mpc5121-psc-uart nodes
+fsl,mpc512x-psc-uart nodes
 --------------------------
 
 Required properties :
- - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
- - cell-index : Index of the PSC in hardware
+ - compatible : Should contain "fsl,<soc>-psc-uart" and "fsl,<soc>-psc"
+   Supported <soc>s: mpc5121, mpc5125
  - reg : Offset and length of the register set for the PSC device
  - interrupts : <a b> where a is the interrupt number of the
    PSC FIFO Controller and b is a field that represents an
@@ -25,12 +25,21 @@ Recommended properties :
  - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
  - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
 
+PSC in SPI mode
+---------------
 
-fsl,mpc5121-psc-fifo node
+Similar to the UART mode a PSC can be operated in SPI mode. The compatible used
+for that is fsl,mpc5121-psc-spi. It requires a fsl,mpc5121-psc-fifo as well.
+The required and recommended properties are identical to the
+fsl,mpc5121-psc-uart nodes, just use spi instead of uart in the compatible
+string.
+
+fsl,mpc512x-psc-fifo node
 -------------------------
 
 Required properties :
- - compatible : Should be "fsl,mpc5121-psc-fifo"
+ - compatible : Should be "fsl,<soc>-psc-fifo"
+   Supported <soc>s: mpc5121, mpc5125
  - reg : Offset and length of the register set for the PSC
          FIFO Controller
  - interrupts : <a b> where a is the interrupt number of the
@@ -39,6 +48,9 @@ Required properties :
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
+Recommended properties :
+ - clocks : specifies the clock needed to operate the fifo controller
+ - clock-names : name(s) for the clock(s) listed in clocks
 
 Example for a board using PSC0 and PSC1 devices in serial mode:
 
index 829bd26d17f86e753ca54f2a4750fd86db61a641..519e97c8f1b8c2029c30785cc39a97ae317e9e64 100644 (file)
@@ -3,11 +3,13 @@ MT8173 with MAX98090 CODEC
 Required properties:
 - compatible : "mediatek,mt8173-max98090"
 - mediatek,audio-codec: the phandle of the MAX98090 audio codec
+- mediatek,platform: the phandle of MT8173 ASoC platform
 
 Example:
 
        sound {
                compatible = "mediatek,mt8173-max98090";
                mediatek,audio-codec = <&max98090>;
+               mediatek,platform = <&afe>;
        };
 
index 61e98c976bd4012b99fc218b729e6fc006209b84..f205ce9e31dd5d31e981bac826e1f69e819434ca 100644 (file)
@@ -3,11 +3,13 @@ MT8173 with RT5650 RT5676 CODECS
 Required properties:
 - compatible : "mediatek,mt8173-rt5650-rt5676"
 - mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs
+- mediatek,platform: the phandle of MT8173 ASoC platform
 
 Example:
 
        sound {
                compatible = "mediatek,mt8173-rt5650-rt5676";
                mediatek,audio-codec = <&rt5650 &rt5676>;
+               mediatek,platform = <&afe>;
        };
 
index bd99193e87b9ea2b68d2b81945e4d27a144f9950..204b311e04001075eb6ed3b03807087cebea12e2 100644 (file)
@@ -10,6 +10,8 @@ Required properties:
 Optional properties:
 - cs-gpios : Specifies the gpio pis to be used for chipselects.
 - num-cs : The number of chipselects. If omitted, this will default to 4.
+- reg-io-width : The I/O register width (in bytes) implemented by this
+  device.  Supported values are 2 or 4 (the default).
 
 Child nodes as per the generic SPI binding.
 
index f1ad9c367532437b370b412cb9f5c68b8f73c494..9c696fa66f818eb98144c628aa1b7000f96a6695 100644 (file)
@@ -3,7 +3,7 @@ Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
 Required properties:
 - compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
 - reg: Base address and size of the controllers memory area
-- clocks: phandle to the AHB clock.
+- clocks: phandle of the AHB clock.
 - clock-names: has to be "ahb".
 - #address-cells: <1>, as required by generic SPI binding.
 - #size-cells: <0>, also as required by generic SPI binding.
@@ -12,9 +12,9 @@ Child nodes as per the generic SPI binding.
 
 Example:
 
-       spi@1F000000 {
+       spi@1f000000 {
                compatible = "qca,ar9132-spi", "qca,ar7100-spi";
-               reg = <0x1F000000 0x10>;
+               reg = <0x1f000000 0x10>;
 
                clocks = <&pll 2>;
                clock-names = "ahb";
index 12ecfe9e359956566b95ede24005d2a18844c52c..d1e914adcf6e104856aae9ac023fc57a21292c5b 100644 (file)
@@ -12,6 +12,8 @@ Required properties:
 - compatible:
        - "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family
        - "ti,da830-spi" for SPI used similar to that on DA8xx SoC family
+       - "ti,keystone-spi" for SPI used similar to that on Keystone2 SoC
+               family
 - reg: Offset and length of SPI controller register space
 - num-cs: Number of chip selects. This includes internal as well as
        GPIO chip selects.
index e02fbf18c82cecad21a355cfacd3ae84c1676ac9..494db6012d02f29b3e17aec0f91f0ea6b0b65a28 100644 (file)
@@ -21,6 +21,7 @@ Required properties:
 Optional properties:
 - img,supports-quad-mode: Should be set if the interface supports quad mode
   SPI transfers.
+- spfi-max-frequency: Maximum speed supported by the spfi block.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/spi/spi-mt65xx.txt b/Documentation/devicetree/bindings/spi/spi-mt65xx.txt
new file mode 100644 (file)
index 0000000..dcefc43
--- /dev/null
@@ -0,0 +1,51 @@
+Binding for MTK SPI controller
+
+Required properties:
+- compatible: should be one of the following.
+    - mediatek,mt8173-spi: for mt8173 platforms
+    - mediatek,mt8135-spi: for mt8135 platforms
+    - mediatek,mt6589-spi: for mt6589 platforms
+
+- #address-cells: should be 1.
+
+- #size-cells: should be 0.
+
+- reg: Address and length of the register set for the device
+
+- interrupts: Should contain spi interrupt
+
+- clocks: phandles to input clocks.
+  The first should be <&topckgen CLK_TOP_SPI_SEL>.
+  The second should be one of the following.
+   -  <&clk26m>: specify parent clock 26MHZ.
+   -  <&topckgen CLK_TOP_SYSPLL3_D2>: specify parent clock 109MHZ.
+                                     It's the default one.
+   -  <&topckgen CLK_TOP_SYSPLL4_D2>: specify parent clock 78MHZ.
+   -  <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ.
+   -  <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ.
+
+- clock-names: shall be "spi-clk" for the controller clock, and
+  "parent-clk" for the parent clock.
+
+Optional properties:
+- mediatek,pad-select: specify which pins group(ck/mi/mo/cs) spi
+  controller used, this value should be 0~3, only required for MT8173.
+    0: specify GPIO69,70,71,72 for spi pins.
+    1: specify GPIO102,103,104,105 for spi pins.
+    2: specify GPIO128,129,130,131 for spi pins.
+    3: specify GPIO5,6,7,8 for spi pins.
+
+Example:
+
+- SoC Specific Portion:
+spi: spi@1100a000 {
+       compatible = "mediatek,mt8173-spi";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0 0x1100a000 0 0x1000>;
+       interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>;
+       clocks = <&topckgen CLK_TOP_SPI_SEL>, <&topckgen CLK_TOP_SYSPLL3_D2>;
+       clock-names = "spi-clk", "parent-clk";
+       mediatek,pad-select = <0>;
+       status = "disabled";
+};
index 014f112e2a14e19557878a250e30438fd8f91b73..57fffe33ebfcdef2c9b52831667e147007c9454e 100644 (file)
@@ -35,11 +35,11 @@ temp1_input         Local temperature (1/1000 degree,
 temp[2-9]_input                CPU temperatures (1/1000 degree,
                        0.125 degree resolution)
 
-fan[1-4]_mode          R/W, 0/1 for manual or SmartFan mode
+pwm[1-4]_enable                R/W, 1/2 for manual or SmartFan mode
                        Setting SmartFan mode is supported only if it has been
                        previously configured by BIOS (or configuration EEPROM)
 
-fan[1-4]_pwm           R/O in SmartFan mode, R/W in manual control mode
+pwm[1-4]               R/O in SmartFan mode, R/W in manual control mode
 
 The driver checks sensor control registers and does not export the sensors
 that are not enabled. Anyway, a sensor that is enabled may actually be not
index c86f2f1ae4f6aa2d9af3e3987e8be06fd237dbef..1fec1135791d98c987105872c63b5e96589633d3 100644 (file)
@@ -119,8 +119,10 @@ ALPS Absolute Mode - Protocol Version 2
  byte 5:  0   z6   z5   z4   z3   z2   z1   z0
 
 Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for
-the DualPoint Stick. For non interleaved dualpoint devices the pointingstick
-buttons get reported separately in the PSM, PSR and PSL bits.
+the DualPoint Stick. The M, R and L bits signal the combined status of both
+the pointingstick and touchpad buttons, except for Dell dualpoint devices
+where the pointingstick buttons get reported separately in the PSM, PSR
+and PSL bits.
 
 Dualpoint device -- interleaved packet format
 ---------------------------------------------
index e63b446d973cd716097adb60295577fe558f3f96..13f888a02a3de5cb7ecfdb2ed03eb1d721601de9 100644 (file)
@@ -952,6 +952,14 @@ When kbuild executes, the following steps are followed (roughly):
        $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic
        mode) if this option is supported by $(AR).
 
+    ARCH_CPPFLAGS, ARCH_AFLAGS, ARCH_CFLAGS   Overrides the kbuild defaults
+
+       These variables are appended to the KBUILD_CPPFLAGS,
+       KBUILD_AFLAGS, and KBUILD_CFLAGS, respectively, after the
+       top-level Makefile has set any other flags. This provides a
+       means for an architecture to override the defaults.
+
+
 --- 6.2 Add prerequisites to archheaders:
 
        The archheaders: rule is used to generate header files that
index f732a8321e8a75274a308bf6a6220a588cf00780..8cc17ca718131656aac98d0946ffa2ecad5a1dc8 100644 (file)
@@ -410,8 +410,17 @@ Documentation/usb/persist.txt.
 
 Q: Can I suspend-to-disk using a swap partition under LVM?
 
-A: No. You can suspend successfully, but you'll not be able to
-resume. uswsusp should be able to work with LVM. See suspend.sf.net.
+A: Yes and No.  You can suspend successfully, but the kernel will not be able
+to resume on its own.  You need an initramfs that can recognize the resume
+situation, activate the logical volume containing the swap volume (but not
+touch any filesystems!), and eventually call
+
+echo -n "$major:$minor" > /sys/power/resume
+
+where $major and $minor are the respective major and minor device numbers of
+the swap volume.
+
+uswsusp works with LVM, too.  See http://suspend.sourceforge.net/
 
 Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
 compiled with the similar configuration files. Anyway I found that
index 949de191fcdc1939c9b160eb7a809afcdbc847af..cda56df9b8a7ce591f3eb254cad1d423c0a856c5 100755 (executable)
@@ -199,7 +199,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "#include <linux/string.h>\n"
        buf += "#include <linux/configfs.h>\n"
        buf += "#include <linux/ctype.h>\n"
-       buf += "#include <asm/unaligned.h>\n\n"
+       buf += "#include <asm/unaligned.h>\n"
+       buf += "#include <scsi/scsi_proto.h>\n\n"
        buf += "#include <target/target_core_base.h>\n"
        buf += "#include <target/target_core_fabric.h>\n"
        buf += "#include <target/target_core_fabric_configfs.h>\n"
@@ -230,8 +231,14 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        }\n"
        buf += "        tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
        buf += "        tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n"
-       buf += "        ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n"
-       buf += "                                &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n"
+
+       if proto_ident == "FC":
+               buf += "        ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP);\n"
+       elif proto_ident == "SAS":
+               buf += "        ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n"
+       elif proto_ident == "iSCSI":
+               buf += "        ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_ISCSI);\n"
+
        buf += "        if (ret < 0) {\n"
        buf += "                kfree(tpg);\n"
        buf += "                return NULL;\n"
@@ -292,7 +299,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
 
        buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
        buf += "        .module                         = THIS_MODULE,\n"
-       buf += "        .name                           = " + fabric_mod_name + ",\n"
+       buf += "        .name                           = \"" + fabric_mod_name + "\",\n"
        buf += "        .get_fabric_name                = " + fabric_mod_name + "_get_fabric_name,\n"
        buf += "        .tpg_get_wwn                    = " + fabric_mod_name + "_get_fabric_wwn,\n"
        buf += "        .tpg_get_tag                    = " + fabric_mod_name + "_get_tag,\n"
@@ -322,17 +329,17 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .fabric_make_tpg                = " + fabric_mod_name + "_make_tpg,\n"
        buf += "        .fabric_drop_tpg                = " + fabric_mod_name + "_drop_tpg,\n"
        buf += "\n"
-       buf += "        .tfc_wwn_attrs                  = " + fabric_mod_name + "_wwn_attrs;\n"
+       buf += "        .tfc_wwn_attrs                  = " + fabric_mod_name + "_wwn_attrs,\n"
        buf += "};\n\n"
 
        buf += "static int __init " + fabric_mod_name + "_init(void)\n"
        buf += "{\n"
-       buf += "        return target_register_template(" + fabric_mod_name + "_ops);\n"
+       buf += "        return target_register_template(&" + fabric_mod_name + "_ops);\n"
        buf += "};\n\n"
 
        buf += "static void __exit " + fabric_mod_name + "_exit(void)\n"
        buf += "{\n"
-       buf += "        target_unregister_template(" + fabric_mod_name + "_ops);\n"
+       buf += "        target_unregister_template(&" + fabric_mod_name + "_ops);\n"
        buf += "};\n\n"
 
        buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"
index 8133cefb6b6e28715197a86aad555c29edbb7aa1..569568f6644f2092211b7bb2690c7defe49977dd 100644 (file)
@@ -361,11 +361,11 @@ S:        Supported
 F:     drivers/input/touchscreen/ad7879.c
 
 ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 S:     Maintained
 
 ADM1025 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/adm1025
@@ -430,7 +430,7 @@ S:  Maintained
 F:     drivers/macintosh/therm_adt746x.c
 
 ADT7475 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/adt7475
@@ -445,7 +445,7 @@ F:  drivers/input/misc/adxl34x.c
 
 ADVANSYS SCSI DRIVER
 M:     Matthew Wilcox <matthew@wil.cx>
-M:     Hannes Reinecke <hare@suse.de>
+M:     Hannes Reinecke <hare@suse.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 F:     Documentation/scsi/advansys.txt
@@ -506,7 +506,7 @@ F:  drivers/scsi/aha152x*
 F:     drivers/scsi/pcmcia/aha152x*
 
 AIC7XXX / AIC79XX SCSI DRIVER
-M:     Hannes Reinecke <hare@suse.de>
+M:     Hannes Reinecke <hare@suse.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 F:     drivers/scsi/aic7xxx/
@@ -746,7 +746,7 @@ S:  Maintained
 F:     sound/aoa/
 
 APM DRIVER
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 S:     Odd fixes
 F:     arch/x86/kernel/apm_32.c
 F:     include/linux/apm_bios.h
@@ -1001,6 +1001,7 @@ 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
@@ -1324,7 +1325,7 @@ 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.cz>
+M:     Tomas Cech <sleep_walker@suse.com>
 L:     linux-arm-kernel@lists.infradead.org
 W:     http://hackndev.com
 S:     Maintained
@@ -1614,6 +1615,7 @@ M:        Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/boot/dts/vexpress*
+F:     arch/arm64/boot/dts/arm/vexpress*
 F:     arch/arm/mach-vexpress/
 F:     */*/vexpress*
 F:     */*/*/vexpress*
@@ -2404,7 +2406,7 @@ F:        drivers/gpio/gpio-bt8xx.c
 BTRFS FILE SYSTEM
 M:     Chris Mason <clm@fb.com>
 M:     Josef Bacik <jbacik@fb.com>
-M:     David Sterba <dsterba@suse.cz>
+M:     David Sterba <dsterba@suse.com>
 L:     linux-btrfs@vger.kernel.org
 W:     http://btrfs.wiki.kernel.org/
 Q:     http://patchwork.kernel.org/project/linux-btrfs/list/
@@ -2562,19 +2564,31 @@ F:      arch/powerpc/include/uapi/asm/spu*.h
 F:     arch/powerpc/oprofile/*cell*
 F:     arch/powerpc/platforms/cell/
 
-CEPH DISTRIBUTED FILE SYSTEM CLIENT
+CEPH COMMON CODE (LIBCEPH)
+M:     Ilya Dryomov <idryomov@gmail.com>
 M:     "Yan, Zheng" <zyan@redhat.com>
 M:     Sage Weil <sage@redhat.com>
 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/filesystems/ceph.txt
-F:     fs/ceph/
 F:     net/ceph/
 F:     include/linux/ceph/
 F:     include/linux/crush/
 
+CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
+M:     "Yan, Zheng" <zyan@redhat.com>
+M:     Sage Weil <sage@redhat.com>
+M:     Ilya Dryomov <idryomov@gmail.com>
+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/filesystems/ceph.txt
+F:     fs/ceph/
+
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
 L:     linux-usb@vger.kernel.org
 S:     Orphan
@@ -2735,7 +2749,7 @@ COCCINELLE/Semantic Patches (SmPL)
 M:     Julia Lawall <Julia.Lawall@lip6.fr>
 M:     Gilles Muller <Gilles.Muller@lip6.fr>
 M:     Nicolas Palix <nicolas.palix@imag.fr>
-M:     Michal Marek <mmarek@suse.cz>
+M:     Michal Marek <mmarek@suse.com>
 L:     cocci@systeme.lip6.fr (moderated for non-subscribers)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git misc
 W:     http://coccinelle.lip6.fr/
@@ -2851,7 +2865,7 @@ F:        kernel/cpuset.c
 
 CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
 M:     Johannes Weiner <hannes@cmpxchg.org>
-M:     Michal Hocko <mhocko@suse.cz>
+M:     Michal Hocko <mhocko@kernel.org>
 L:     cgroups@vger.kernel.org
 L:     linux-mm@kvack.org
 S:     Maintained
@@ -2932,7 +2946,7 @@ F:        arch/x86/kernel/cpuid.c
 F:     arch/x86/kernel/msr.c
 
 CPU POWER MONITORING SUBSYSTEM
-M:     Thomas Renninger <trenn@suse.de>
+M:     Thomas Renninger <trenn@suse.com>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
 F:     tools/power/cpupower/
@@ -3162,7 +3176,7 @@ F:        Documentation/networking/dmfe.txt
 F:     drivers/net/ethernet/dec/tulip/dmfe.c
 
 DC390/AM53C974 SCSI driver
-M:     Hannes Reinecke <hare@suse.de>
+M:     Hannes Reinecke <hare@suse.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 F:     drivers/scsi/am53c974.c
@@ -3366,7 +3380,7 @@ W:        http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
 S:     Maintained
 
 DISKQUOTA
-M:     Jan Kara <jack@suse.cz>
+M:     Jan Kara <jack@suse.com>
 S:     Maintained
 F:     Documentation/filesystems/quota.txt
 F:     fs/quota/
@@ -3422,7 +3436,7 @@ F:        Documentation/hwmon/dme1737
 F:     drivers/hwmon/dme1737.c
 
 DMI/SMBIOS SUPPORT
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 S:     Maintained
 T:     quilt http://jdelvare.nerim.net/devel/linux/jdelvare-dmi/
 F:     Documentation/ABI/testing/sysfs-firmware-dmi-tables
@@ -3573,6 +3587,15 @@ S:       Maintained
 F:     drivers/gpu/drm/rockchip/
 F:     Documentation/devicetree/bindings/video/rockchip*
 
+DRM DRIVERS FOR STI
+M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M:     Vincent Abriou <vincent.abriou@st.com>
+L:     dri-devel@lists.freedesktop.org
+T:     git http://git.linaro.org/people/benjamin.gaignard/kernel.git
+S:     Maintained
+F:     drivers/gpu/drm/sti
+F:     Documentation/devicetree/bindings/gpu/st,stih4xx.txt
+
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -4038,7 +4061,7 @@ F:        drivers/of/of_mdio.c
 F:     drivers/of/of_net.c
 
 EXT2 FILE SYSTEM
-M:     Jan Kara <jack@suse.cz>
+M:     Jan Kara <jack@suse.com>
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/ext2.txt
@@ -4046,7 +4069,7 @@ F:        fs/ext2/
 F:     include/linux/ext2*
 
 EXT3 FILE SYSTEM
-M:     Jan Kara <jack@suse.cz>
+M:     Jan Kara <jack@suse.com>
 M:     Andrew Morton <akpm@linux-foundation.org>
 M:     Andreas Dilger <adilger.kernel@dilger.ca>
 L:     linux-ext4@vger.kernel.org
@@ -4096,7 +4119,7 @@ F:        drivers/video/fbdev/exynos/exynos_mipi*
 F:     include/video/exynos_mipi*
 
 F71805F HARDWARE MONITORING DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/f71805f
@@ -4231,7 +4254,7 @@ S:        Maintained
 F:     drivers/block/rsxx/
 
 FLOPPY DRIVER
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git
 S:     Odd fixes
 F:     drivers/block/floppy.c
@@ -4652,7 +4675,7 @@ F:        drivers/media/usb/stk1160/
 
 H8/300 ARCHITECTURE
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
-L:     uclinux-h8-devel@lists.sourceforge.jp
+L:     uclinux-h8-devel@lists.sourceforge.jp (moderated for non-subscribers)
 W:     http://uclinux-h8.sourceforge.jp
 T:     git git://git.sourceforge.jp/gitroot/uclinux-h8/linux.git
 S:     Maintained
@@ -4699,7 +4722,7 @@ S:        Maintained
 F:     drivers/media/usb/hackrf/
 
 HARDWARE MONITORING
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
@@ -4802,7 +4825,7 @@ F:        include/linux/pm.h
 F:     arch/*/include/asm/suspend*.h
 
 HID CORE LAYER
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 L:     linux-input@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
 S:     Maintained
@@ -4811,7 +4834,7 @@ F:        include/linux/hid*
 F:     include/uapi/linux/hid*
 
 HID SENSOR HUB DRIVERS
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 M:     Jonathan Cameron <jic23@kernel.org>
 M:     Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
 L:     linux-input@vger.kernel.org
@@ -4945,7 +4968,7 @@ F:        include/linux/hyperv.h
 F:     tools/hv/
 
 I2C OVER PARALLEL PORT
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     Documentation/i2c/busses/i2c-parport
@@ -4954,7 +4977,7 @@ F:        drivers/i2c/busses/i2c-parport.c
 F:     drivers/i2c/busses/i2c-parport-light.c
 
 I2C/SMBUS CONTROLLER DRIVERS FOR PC
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     Documentation/i2c/busses/i2c-ali1535
@@ -4995,7 +5018,7 @@ F:        drivers/i2c/busses/i2c-ismt.c
 F:     Documentation/i2c/busses/i2c-ismt
 
 I2C/SMBUS STUB DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/i2c-stub.c
@@ -5022,7 +5045,7 @@ L:        linux-acpi@vger.kernel.org
 S:     Maintained
 
 I2C-TAOS-EVM DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     Documentation/i2c/busses/i2c-taos-evm
@@ -5551,8 +5574,8 @@ F:        include/uapi/linux/ip_vs.h
 F:     net/netfilter/ipvs/
 
 IPWIRELESS DRIVER
-M:     Jiri Kosina <jkosina@suse.cz>
-M:     David Sterba <dsterba@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
+M:     David Sterba <dsterba@suse.com>
 S:     Odd Fixes
 F:     drivers/tty/ipwireless/
 
@@ -5586,6 +5609,7 @@ F:        kernel/irq/
 IRQCHIP DRIVERS
 M:     Thomas Gleixner <tglx@linutronix.de>
 M:     Jason Cooper <jason@lakedaemon.net>
+M:     Marc Zyngier <marc.zyngier@arm.com>
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
@@ -5594,11 +5618,14 @@ F:      Documentation/devicetree/bindings/interrupt-controller/
 F:     drivers/irqchip/
 
 IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
-M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
+M:     Jiang Liu <jiang.liu@linux.intel.com>
+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
 
 ISAPNP
 M:     Jaroslav Kysela <perex@perex.cz>
@@ -5672,7 +5699,7 @@ S:        Maintained
 F:     drivers/isdn/hardware/eicon/
 
 IT87 HARDWARE MONITORING DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/it87
@@ -5739,7 +5766,7 @@ F:        include/uapi/linux/jffs2.h
 
 JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
 M:     Andrew Morton <akpm@linux-foundation.org>
-M:     Jan Kara <jack@suse.cz>
+M:     Jan Kara <jack@suse.com>
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
 F:     fs/jbd/
@@ -5803,7 +5830,7 @@ S:        Maintained
 F:     fs/autofs4/
 
 KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
-M:     Michal Marek <mmarek@suse.cz>
+M:     Michal Marek <mmarek@suse.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git for-next
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git rc-fixes
 L:     linux-kbuild@vger.kernel.org
@@ -5867,7 +5894,7 @@ F:        arch/x86/include/asm/svm.h
 F:     arch/x86/kvm/svm.c
 
 KERNEL VIRTUAL MACHINE (KVM) FOR POWERPC
-M:     Alexander Graf <agraf@suse.de>
+M:     Alexander Graf <agraf@suse.com>
 L:     kvm-ppc@vger.kernel.org
 W:     http://kvm.qumranet.com
 T:     git git://github.com/agraf/linux-2.6.git
@@ -5885,7 +5912,6 @@ S:        Supported
 F:     Documentation/s390/kvm.txt
 F:     arch/s390/include/asm/kvm*
 F:     arch/s390/kvm/
-F:     drivers/s390/kvm/
 
 KERNEL VIRTUAL MACHINE (KVM) FOR ARM
 M:     Christoffer Dall <christoffer.dall@linaro.org>
@@ -6024,7 +6050,7 @@ F:        drivers/leds/
 F:     include/linux/leds.h
 
 LEGACY EEPROM DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 S:     Maintained
 F:     Documentation/misc-devices/eeprom
 F:     drivers/misc/eeprom/eeprom.c
@@ -6077,7 +6103,7 @@ F:        include/linux/ata.h
 F:     include/linux/libata.h
 
 LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <vireshk@kernel.org>
 L:     linux-ide@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 S:     Maintained
@@ -6147,6 +6173,7 @@ L:        linux-nvdimm@lists.01.org
 Q:     https://patchwork.kernel.org/project/linux-nvdimm/list/
 S:     Supported
 F:     drivers/nvdimm/pmem.c
+F:     include/linux/pmem.h
 
 LINUX FOR IBM pSERIES (RS/6000)
 M:     Paul Mackerras <paulus@au.ibm.com>
@@ -6161,7 +6188,7 @@ M:        Michael Ellerman <mpe@ellerman.id.au>
 W:     http://www.penguinppc.org/
 L:     linuxppc-dev@lists.ozlabs.org
 Q:     http://patchwork.ozlabs.org/project/linuxppc-dev/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
 S:     Supported
 F:     Documentation/powerpc/
 F:     arch/powerpc/
@@ -6237,8 +6264,8 @@ F:        drivers/platform/x86/hp_accel.c
 LIVE PATCHING
 M:     Josh Poimboeuf <jpoimboe@redhat.com>
 M:     Seth Jennings <sjenning@redhat.com>
-M:     Jiri Kosina <jkosina@suse.cz>
-M:     Vojtech Pavlik <vojtech@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
+M:     Vojtech Pavlik <vojtech@suse.com>
 S:     Maintained
 F:     kernel/livepatch/
 F:     include/linux/livepatch.h
@@ -6264,21 +6291,21 @@ S:      Maintained
 F:     drivers/hwmon/lm73.c
 
 LM78 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/lm78
 F:     drivers/hwmon/lm78.c
 
 LM83 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/lm83
 F:     drivers/hwmon/lm83.c
 
 LM90 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/lm90
@@ -6824,6 +6851,12 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/usb/msi2500/
 
+MSYSTEMS DISKONCHIP G3 MTD DRIVER
+M:     Robert Jarzmik <robert.jarzmik@free.fr>
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+F:     drivers/mtd/devices/docg3*
+
 MT9M032 APTINA SENSOR DRIVER
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-media@vger.kernel.org
@@ -7005,6 +7038,7 @@ F:        include/uapi/linux/netfilter/
 F:     net/*/netfilter.c
 F:     net/*/netfilter/
 F:     net/netfilter/
+F:     net/bridge/br_netfilter*.c
 
 NETLABEL
 M:     Paul Moore <paul@paul-moore.com>
@@ -7704,7 +7738,7 @@ S:        Maintained
 F:     drivers/char/pc8736x_gpio.c
 
 PC87427 HARDWARE MONITORING DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/pc87427
@@ -7981,7 +8015,7 @@ S:        Maintained
 F:     drivers/pinctrl/samsung/
 
 PIN CONTROLLER - ST SPEAR
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <vireshk@kernel.org>
 L:     spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
@@ -7989,7 +8023,7 @@ S:        Maintained
 F:     drivers/pinctrl/spear/
 
 PKTCDVD DRIVER
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 S:     Maintained
 F:     drivers/block/pktcdvd.c
 F:     include/linux/pktcdvd.h
@@ -8366,10 +8400,12 @@ RADOS BLOCK DEVICE (RBD)
 M:     Ilya Dryomov <idryomov@gmail.com>
 M:     Sage Weil <sage@redhat.com>
 M:     Alex Elder <elder@kernel.org>
-M:     ceph-devel@vger.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
 
@@ -8878,7 +8914,7 @@ S:        Maintained
 F:     drivers/tty/serial/
 
 SYNOPSYS DESIGNWARE DMAC DRIVER
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <vireshk@kernel.org>
 M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 S:     Maintained
 F:     include/linux/dma/dw.h
@@ -9045,7 +9081,7 @@ S:        Maintained
 F:     drivers/mmc/host/sdhci-s3c*
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <vireshk@kernel.org>
 L:     spear-devel@list.st.com
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
@@ -9407,7 +9443,7 @@ F:        Documentation/hwmon/sch5627
 F:     drivers/hwmon/sch5627.c
 
 SMSC47B397 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/smsc47b397
@@ -9456,7 +9492,7 @@ S:        Supported
 F:     drivers/media/pci/solo6x10/
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
-M:     Neil Brown <neilb@suse.de>
+M:     Neil Brown <neilb@suse.com>
 L:     linux-raid@vger.kernel.org
 S:     Supported
 F:     drivers/md/
@@ -9499,7 +9535,7 @@ F:        drivers/memstick/core/ms_block.*
 
 SOUND
 M:     Jaroslav Kysela <perex@perex.cz>
-M:     Takashi Iwai <tiwai@suse.de>
+M:     Takashi Iwai <tiwai@suse.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://www.alsa-project.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
@@ -9583,7 +9619,7 @@ S:        Maintained
 F:     include/linux/compiler.h
 
 SPEAR PLATFORM SUPPORT
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <vireshk@kernel.org>
 M:     Shiraz Hashim <shiraz.linux.kernel@gmail.com>
 L:     spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -9592,7 +9628,7 @@ S:        Maintained
 F:     arch/arm/mach-spear/
 
 SPEAR CLOCK FRAMEWORK SUPPORT
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <vireshk@kernel.org>
 L:     spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
@@ -10382,7 +10418,7 @@ K:      ^Subject:.*(?i)trivial
 
 TTY LAYER
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-M:     Jiri Slaby <jslaby@suse.cz>
+M:     Jiri Slaby <jslaby@suse.com>
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:     Documentation/serial/
@@ -10456,7 +10492,7 @@ F:      arch/m68k/*/*_no.*
 F:     arch/m68k/include/asm/*_no.*
 
 UDF FILESYSTEM
-M:     Jan Kara <jack@suse.cz>
+M:     Jan Kara <jack@suse.com>
 S:     Maintained
 F:     Documentation/filesystems/udf.txt
 F:     fs/udf/
@@ -10599,7 +10635,7 @@ F:      drivers/usb/gadget/
 F:     include/linux/usb/gadget*
 
 USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
-M:     Jiri Kosina <jkosina@suse.cz>
+M:     Jiri Kosina <jkosina@suse.com>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
 S:     Maintained
@@ -10724,7 +10760,7 @@ S:      Maintained
 F:     drivers/usb/host/uhci*
 
 USB "USBNET" DRIVER FRAMEWORK
-M:     Oliver Neukum <oneukum@suse.de>
+M:     Oliver Neukum <oneukum@suse.com>
 L:     netdev@vger.kernel.org
 W:     http://www.linux-usb.org/usbnet
 S:     Maintained
@@ -10878,6 +10914,15 @@ F:     drivers/block/virtio_blk.c
 F:     include/linux/virtio_*.h
 F:     include/uapi/linux/virtio_*.h
 
+VIRTIO DRIVERS FOR S390
+M:     Christian Borntraeger <borntraeger@de.ibm.com>
+M:     Cornelia Huck <cornelia.huck@de.ibm.com>
+L:     linux-s390@vger.kernel.org
+L:     virtualization@lists.linux-foundation.org
+L:     kvm@vger.kernel.org
+S:     Supported
+F:     drivers/s390/virtio/
+
 VIRTIO GPU DRIVER
 M:     David Airlie <airlied@linux.ie>
 M:     Gerd Hoffmann <kraxel@redhat.com>
@@ -11051,7 +11096,7 @@ F:      Documentation/hwmon/w83793
 F:     drivers/hwmon/w83793.c
 
 W83795 HARDWARE MONITORING DRIVER
-M:     Jean Delvare <jdelvare@suse.de>
+M:     Jean Delvare <jdelvare@suse.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     drivers/hwmon/w83795.c
index 13270c0a93363f079ccc3a112bfa7d7d80c7f429..246053f04fb5cecf72e477cd94257e052955d21f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc8
 NAME = Hurr durr I'ma sheep
 
 # *DOCUMENTATION*
@@ -597,6 +597,11 @@ endif # $(dot-config)
 # Defaults to vmlinux, but the arch makefile usually adds further targets
 all: vmlinux
 
+# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
+# values of the respective KBUILD_* variables
+ARCH_CPPFLAGS :=
+ARCH_AFLAGS :=
+ARCH_CFLAGS :=
 include arch/$(SRCARCH)/Makefile
 
 KBUILD_CFLAGS  += $(call cc-option,-fno-delete-null-pointer-checks,)
@@ -780,10 +785,11 @@ endif
 include scripts/Makefile.kasan
 include scripts/Makefile.extrawarn
 
-# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
-KBUILD_CPPFLAGS += $(KCPPFLAGS)
-KBUILD_AFLAGS += $(KAFLAGS)
-KBUILD_CFLAGS += $(KCFLAGS)
+# Add any arch overrides and user supplied CPPFLAGS, AFLAGS and CFLAGS as the
+# last assignments
+KBUILD_CPPFLAGS += $(ARCH_CPPFLAGS) $(KCPPFLAGS)
+KBUILD_AFLAGS   += $(ARCH_AFLAGS)   $(KAFLAGS)
+KBUILD_CFLAGS   += $(ARCH_CFLAGS)   $(KCFLAGS)
 
 # Use --build-id when available.
 LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
@@ -847,10 +853,10 @@ export mod_strip_cmd
 mod_compress_cmd = true
 ifdef CONFIG_MODULE_COMPRESS
   ifdef CONFIG_MODULE_COMPRESS_GZIP
-    mod_compress_cmd = gzip -n
+    mod_compress_cmd = gzip -n -f
   endif # CONFIG_MODULE_COMPRESS_GZIP
   ifdef CONFIG_MODULE_COMPRESS_XZ
-    mod_compress_cmd = xz
+    mod_compress_cmd = xz -f
   endif # CONFIG_MODULE_COMPRESS_XZ
 endif # CONFIG_MODULE_COMPRESS
 export mod_compress_cmd
index bec6666a3cc466c81baea023dcd010a65d3d8181..8a8ea7110de84482a5c33e53a50d0fc908998f3e 100644 (file)
@@ -221,6 +221,10 @@ config ARCH_TASK_STRUCT_ALLOCATOR
 config ARCH_THREAD_INFO_ALLOCATOR
        bool
 
+# Select if arch wants to size task_struct dynamically via arch_task_struct_size:
+config ARCH_WANTS_DYNAMIC_TASK_STRUCT
+       bool
+
 config HAVE_REGS_AND_STACK_ACCESS_API
        bool
        help
index cde23cd03609afe5fce911421cc384485368ba64..ffd9cf5ec8c407c4686c519de89b3e827f1656a2 100644 (file)
@@ -5,6 +5,7 @@ generic-y += cputime.h
 generic-y += exec.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += preempt.h
 generic-y += sections.h
 generic-y += trace_clock.h
diff --git a/arch/alpha/include/asm/mm-arch-hooks.h b/arch/alpha/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index b07fd86..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_ALPHA_MM_ARCH_HOOKS_H
-#define _ASM_ALPHA_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_ALPHA_MM_ARCH_HOOKS_H */
index e7cee0a5c56dfa80222d8286a63342b10c07bc42..bd4670d1b89bcabf043f13015c01b59397b73427 100644 (file)
@@ -115,6 +115,7 @@ if ISA_ARCOMPACT
 
 config ARC_CPU_750D
        bool "ARC750D"
+       select ARC_CANT_LLSC
        help
          Support for ARC750 core
 
@@ -312,11 +313,11 @@ config ARC_PAGE_SIZE_8K
 
 config ARC_PAGE_SIZE_16K
        bool "16KB"
-       depends on ARC_MMU_V3
+       depends on ARC_MMU_V3 || ARC_MMU_V4
 
 config ARC_PAGE_SIZE_4K
        bool "4KB"
-       depends on ARC_MMU_V3
+       depends on ARC_MMU_V3 || ARC_MMU_V4
 
 endchoice
 
@@ -362,7 +363,12 @@ config ARC_CANT_LLSC
 config ARC_HAS_LLSC
        bool "Insn: LLOCK/SCOND (efficient atomic ops)"
        default y
-       depends on !ARC_CPU_750D && !ARC_CANT_LLSC
+       depends on !ARC_CANT_LLSC
+
+config ARC_STAR_9000923308
+       bool "Workaround for llock/scond livelock"
+       default y
+       depends on ISA_ARCV2 && SMP && ARC_HAS_LLSC
 
 config ARC_HAS_SWAPE
        bool "Insn: SWAPE (endian-swap)"
@@ -378,6 +384,10 @@ config ARC_HAS_LL64
          dest operands with 2 possible source operands.
        default y
 
+config ARC_HAS_DIV_REM
+       bool "Insn: div, divu, rem, remu"
+       default y
+
 config ARC_HAS_RTC
        bool "Local 64-bit r/o cycle counter"
        default n
index 6107062c01115dbea8a56e02bce254a8ba5b91af..8a27a48304a4c0127d97996d73c7d7dc0515d8a3 100644 (file)
@@ -36,8 +36,16 @@ cflags-$(atleast_gcc44)                      += -fsection-anchors
 cflags-$(CONFIG_ARC_HAS_LLSC)          += -mlock
 cflags-$(CONFIG_ARC_HAS_SWAPE)         += -mswape
 
+ifdef CONFIG_ISA_ARCV2
+
 ifndef CONFIG_ARC_HAS_LL64
-cflags-$(CONFIG_ISA_ARCV2)             += -mno-ll64
+cflags-y                               += -mno-ll64
+endif
+
+ifndef CONFIG_ARC_HAS_DIV_REM
+cflags-y                               += -mno-div-rem
+endif
+
 endif
 
 cflags-$(CONFIG_ARC_DW2_UNWIND)                += -fasynchronous-unwind-tables
@@ -49,7 +57,8 @@ endif
 
 ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
 # Generic build system uses -O2, we want -O3
-cflags-y  += -O3
+# Note: No need to add to cflags-y as that happens anyways
+ARCH_CFLAGS += -O3
 endif
 
 # small data is default for elf32 tool-chain. If not usable, disable it
index 15c8d6226c9d8508b54fbecc6547f5c0a0529e14..1cd5e82f5dc2c6f74cb36d40632998fd26195426 100644 (file)
@@ -12,7 +12,7 @@
 
 / {
        compatible = "snps,arc";
-       clock-frequency = <75000000>;
+       clock-frequency = <90000000>;
        #address-cells = <1>;
        #size-cells = <1>;
 
index 199d42820eca784b4bd5955d3a7420bc53697774..2f0b33257db2e2ecf4749bee0d2f5ed3260dc3a3 100644 (file)
@@ -12,7 +12,7 @@
 
 / {
        compatible = "snps,arc";
-       clock-frequency = <75000000>;
+       clock-frequency = <90000000>;
        #address-cells = <1>;
        #size-cells = <1>;
 
index 1a80cc91a03ba323f8418dfb705098a00f031671..7611b10a2d238c7b4bb73696b59e2fe8b14ceb2c 100644 (file)
@@ -22,6 +22,7 @@ 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
index 070f58827a5c12c2e19469ff4280f7c69e0f36a3..c8f57b8449dcf6a36aa61cd3589b90ebba42d7ea 100644 (file)
 #define ECR_C_BIT_DTLB_LD_MISS         8
 #define ECR_C_BIT_DTLB_ST_MISS         9
 
-
 /* Auxiliary registers */
 #define AUX_IDENTITY           4
 #define AUX_INTR_VEC_BASE      0x25
-
+#define AUX_NON_VOL            0x5e
 
 /*
  * Floating Pt Registers
@@ -240,9 +239,9 @@ struct bcr_extn_xymem {
 
 struct bcr_perip {
 #ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int start:8, pad2:8, sz:8, pad:8;
+       unsigned int start:8, pad2:8, sz:8, ver:8;
 #else
-       unsigned int pad:8, sz:8, pad2:8, start:8;
+       unsigned int ver:8, sz:8, pad2:8, start:8;
 #endif
 };
 
index 03484cb4d16d2eb4fada0095ee427726c23bd2e1..87d18ae53115596f7b64a56a4a07a572d54c3cbd 100644 (file)
 
 #define atomic_set(v, i) (((v)->counter) = (i))
 
-#ifdef CONFIG_ISA_ARCV2
-#define PREFETCHW      "       prefetchw   [%1]        \n"
-#else
-#define PREFETCHW
+#ifdef CONFIG_ARC_STAR_9000923308
+
+#define SCOND_FAIL_RETRY_VAR_DEF                                               \
+       unsigned int delay = 1, tmp;                                            \
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "       bz      4f                      \n"                             \
+       "   ; --- scond fail delay ---          \n"                             \
+       "       mov     %[tmp], %[delay]        \n"     /* tmp = delay */       \
+       "2:     brne.d  %[tmp], 0, 2b           \n"     /* while (tmp != 0) */  \
+       "       sub     %[tmp], %[tmp], 1       \n"     /* tmp-- */             \
+       "       rol     %[delay], %[delay]      \n"     /* delay *= 2 */        \
+       "       b       1b                      \n"     /* start over */        \
+       "4: ; --- success ---                   \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS                                                  \
+         ,[delay] "+&r" (delay),[tmp] "=&r"    (tmp)                           \
+
+#else  /* !CONFIG_ARC_STAR_9000923308 */
+
+#define SCOND_FAIL_RETRY_VAR_DEF
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "       bnz     1b                      \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS
+
 #endif
 
 #define ATOMIC_OP(op, c_op, asm_op)                                    \
 static inline void atomic_##op(int i, atomic_t *v)                     \
 {                                                                      \
-       unsigned int temp;                                              \
+       unsigned int val;                                               \
+       SCOND_FAIL_RETRY_VAR_DEF                                        \
                                                                        \
        __asm__ __volatile__(                                           \
-       "1:                             \n"                             \
-       PREFETCHW                                                       \
-       "       llock   %0, [%1]        \n"                             \
-       "       " #asm_op " %0, %0, %2  \n"                             \
-       "       scond   %0, [%1]        \n"                             \
-       "       bnz     1b              \n"                             \
-       : "=&r"(temp)   /* Early clobber, to prevent reg reuse */       \
-       : "r"(&v->counter), "ir"(i)                                     \
+       "1:     llock   %[val], [%[ctr]]                \n"             \
+       "       " #asm_op " %[val], %[val], %[i]        \n"             \
+       "       scond   %[val], [%[ctr]]                \n"             \
+       "                                               \n"             \
+       SCOND_FAIL_RETRY_ASM                                            \
+                                                                       \
+       : [val] "=&r"   (val) /* Early clobber to prevent reg reuse */  \
+         SCOND_FAIL_RETRY_VARS                                         \
+       : [ctr] "r"     (&v->counter), /* Not "m": llock only supports reg direct addr mode */  \
+         [i]   "ir"    (i)                                             \
        : "cc");                                                        \
 }                                                                      \
 
 #define ATOMIC_OP_RETURN(op, c_op, asm_op)                             \
 static inline int atomic_##op##_return(int i, atomic_t *v)             \
 {                                                                      \
-       unsigned int temp;                                              \
+       unsigned int val;                                               \
+       SCOND_FAIL_RETRY_VAR_DEF                                        \
                                                                        \
        /*                                                              \
         * Explicit full memory barrier needed before/after as          \
@@ -58,19 +85,21 @@ static inline int atomic_##op##_return(int i, atomic_t *v)          \
        smp_mb();                                                       \
                                                                        \
        __asm__ __volatile__(                                           \
-       "1:                             \n"                             \
-       PREFETCHW                                                       \
-       "       llock   %0, [%1]        \n"                             \
-       "       " #asm_op " %0, %0, %2  \n"                             \
-       "       scond   %0, [%1]        \n"                             \
-       "       bnz     1b              \n"                             \
-       : "=&r"(temp)                                                   \
-       : "r"(&v->counter), "ir"(i)                                     \
+       "1:     llock   %[val], [%[ctr]]                \n"             \
+       "       " #asm_op " %[val], %[val], %[i]        \n"             \
+       "       scond   %[val], [%[ctr]]                \n"             \
+       "                                               \n"             \
+       SCOND_FAIL_RETRY_ASM                                            \
+                                                                       \
+       : [val] "=&r"   (val)                                           \
+         SCOND_FAIL_RETRY_VARS                                         \
+       : [ctr] "r"     (&v->counter),                                  \
+         [i]   "ir"    (i)                                             \
        : "cc");                                                        \
                                                                        \
        smp_mb();                                                       \
                                                                        \
-       return temp;                                                    \
+       return val;                                                     \
 }
 
 #else  /* !CONFIG_ARC_HAS_LLSC */
@@ -150,6 +179,9 @@ ATOMIC_OP(and, &=, and)
 #undef ATOMIC_OPS
 #undef ATOMIC_OP_RETURN
 #undef ATOMIC_OP
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
 
 /**
  * __atomic_add_unless - add unless the number is a given value
index 99fe118d3730bc050263e5be7dd3423ab659d46c..57c1f33844d44f1f9d16ed448ce0b13e87b88cea 100644 (file)
@@ -50,8 +50,7 @@ static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\
         * done for const @nr, but no code is generated due to gcc      \
         * const prop.                                                  \
         */                                                             \
-       if (__builtin_constant_p(nr))                                   \
-               nr &= 0x1f;                                             \
+       nr &= 0x1f;                                                     \
                                                                        \
        __asm__ __volatile__(                                           \
        "1:     llock       %0, [%1]            \n"                     \
@@ -82,8 +81,7 @@ static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *
                                                                        \
        m += nr >> 5;                                                   \
                                                                        \
-       if (__builtin_constant_p(nr))                                   \
-               nr &= 0x1f;                                             \
+       nr &= 0x1f;                                                     \
                                                                        \
        /*                                                              \
         * Explicit full memory barrier needed before/after as          \
@@ -129,16 +127,13 @@ static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\
        unsigned long temp, flags;                                      \
        m += nr >> 5;                                                   \
                                                                        \
-       if (__builtin_constant_p(nr))                                   \
-               nr &= 0x1f;                                             \
-                                                                       \
        /*                                                              \
         * spin lock/unlock provide the needed smp_mb() before/after    \
         */                                                             \
        bitops_lock(flags);                                             \
                                                                        \
        temp = *m;                                                      \
-       *m = temp c_op (1UL << nr);                                     \
+       *m = temp c_op (1UL << (nr & 0x1f));                                    \
                                                                        \
        bitops_unlock(flags);                                           \
 }
@@ -149,17 +144,14 @@ static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *
        unsigned long old, flags;                                       \
        m += nr >> 5;                                                   \
                                                                        \
-       if (__builtin_constant_p(nr))                                   \
-               nr &= 0x1f;                                             \
-                                                                       \
        bitops_lock(flags);                                             \
                                                                        \
        old = *m;                                                       \
-       *m = old c_op (1 << nr);                                        \
+       *m = old c_op (1UL << (nr & 0x1f));                             \
                                                                        \
        bitops_unlock(flags);                                           \
                                                                        \
-       return (old & (1 << nr)) != 0;                                  \
+       return (old & (1UL << (nr & 0x1f))) != 0;                       \
 }
 
 #endif /* CONFIG_ARC_HAS_LLSC */
@@ -174,11 +166,8 @@ static inline void __##op##_bit(unsigned long nr, volatile unsigned long *m)       \
        unsigned long temp;                                             \
        m += nr >> 5;                                                   \
                                                                        \
-       if (__builtin_constant_p(nr))                                   \
-               nr &= 0x1f;                                             \
-                                                                       \
        temp = *m;                                                      \
-       *m = temp c_op (1UL << nr);                                     \
+       *m = temp c_op (1UL << (nr & 0x1f));                            \
 }
 
 #define __TEST_N_BIT_OP(op, c_op, asm_op)                              \
@@ -187,13 +176,10 @@ static inline int __test_and_##op##_bit(unsigned long nr, volatile unsigned long
        unsigned long old;                                              \
        m += nr >> 5;                                                   \
                                                                        \
-       if (__builtin_constant_p(nr))                                   \
-               nr &= 0x1f;                                             \
-                                                                       \
        old = *m;                                                       \
-       *m = old c_op (1 << nr);                                        \
+       *m = old c_op (1UL << (nr & 0x1f));                             \
                                                                        \
-       return (old & (1 << nr)) != 0;                                  \
+       return (old & (1UL << (nr & 0x1f))) != 0;                       \
 }
 
 #define BIT_OPS(op, c_op, asm_op)                                      \
@@ -224,10 +210,7 @@ test_bit(unsigned int nr, const volatile unsigned long *addr)
 
        addr += nr >> 5;
 
-       if (__builtin_constant_p(nr))
-               nr &= 0x1f;
-
-       mask = 1 << nr;
+       mask = 1UL << (nr & 0x1f);
 
        return ((mask & *addr) != 0);
 }
index 05b5aaf5b0f91e5580395e08ae778f5ddace5b3c..70cfe16b742d78f7e8016a41b11271e7d258f7a6 100644 (file)
 #include <linux/uaccess.h>
 #include <asm/errno.h>
 
+#ifdef CONFIG_ARC_HAS_LLSC
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
+                                                       \
+       __asm__ __volatile__(                           \
+       "1:     llock   %1, [%2]                \n"     \
+               insn                            "\n"    \
+       "2:     scond   %0, [%2]                \n"     \
+       "       bnz     1b                      \n"     \
+       "       mov %0, 0                       \n"     \
+       "3:                                     \n"     \
+       "       .section .fixup,\"ax\"          \n"     \
+       "       .align  4                       \n"     \
+       "4:     mov %0, %4                      \n"     \
+       "       b   3b                          \n"     \
+       "       .previous                       \n"     \
+       "       .section __ex_table,\"a\"       \n"     \
+       "       .align  4                       \n"     \
+       "       .word   1b, 4b                  \n"     \
+       "       .word   2b, 4b                  \n"     \
+       "       .previous                       \n"     \
+                                                       \
+       : "=&r" (ret), "=&r" (oldval)                   \
+       : "r" (uaddr), "r" (oparg), "ir" (-EFAULT)      \
+       : "cc", "memory")
+
+#else  /* !CONFIG_ARC_HAS_LLSC */
+
 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
                                                        \
        __asm__ __volatile__(                           \
-       "1:     ld  %1, [%2]                    \n"     \
+       "1:     ld      %1, [%2]                \n"     \
                insn                            "\n"    \
-       "2:     st  %0, [%2]                    \n"     \
+       "2:     st      %0, [%2]                \n"     \
        "       mov %0, 0                       \n"     \
        "3:                                     \n"     \
        "       .section .fixup,\"ax\"          \n"     \
@@ -39,6 +67,8 @@
        : "r" (uaddr), "r" (oparg), "ir" (-EFAULT)      \
        : "cc", "memory")
 
+#endif
+
 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
@@ -123,11 +153,17 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval,
 
        pagefault_disable();
 
-       /* TBD : can use llock/scond */
        __asm__ __volatile__(
-       "1:     ld    %0, [%3]  \n"
-       "       brne  %0, %1, 3f        \n"
-       "2:     st    %2, [%3]  \n"
+#ifdef CONFIG_ARC_HAS_LLSC
+       "1:     llock   %0, [%3]                \n"
+       "       brne    %0, %1, 3f              \n"
+       "2:     scond   %2, [%3]                \n"
+       "       bnz     1b                      \n"
+#else
+       "1:     ld      %0, [%3]                \n"
+       "       brne    %0, %1, 3f              \n"
+       "2:     st      %2, [%3]                \n"
+#endif
        "3:     \n"
        "       .section .fixup,\"ax\"  \n"
        "4:     mov %0, %4      \n"
diff --git a/arch/arc/include/asm/mm-arch-hooks.h b/arch/arc/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index c37541c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_ARC_MM_ARCH_HOOKS_H
-#define _ASM_ARC_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_ARC_MM_ARCH_HOOKS_H */
index 91755972b9a25222c37a36e6b76dfd758cdbe771..69095da1fcfd1e35f16234aaf473896194064d38 100644 (file)
 struct pt_regs {
 
        /* Real registers */
-       long bta;       /* bta_l1, bta_l2, erbta */
+       unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       long lp_start, lp_end, lp_count;
+       unsigned long lp_start, lp_end, lp_count;
 
-       long status32;  /* status32_l1, status32_l2, erstatus */
-       long ret;       /* ilink1, ilink2 or eret */
-       long blink;
-       long fp;
-       long r26;       /* gp */
+       unsigned long status32; /* status32_l1, status32_l2, erstatus */
+       unsigned long ret;      /* ilink1, ilink2 or eret */
+       unsigned long blink;
+       unsigned long fp;
+       unsigned long r26;      /* gp */
 
-       long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+       unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
 
-       long sp;        /* user/kernel sp depending on where we came from  */
-       long orig_r0;
+       unsigned long sp;       /* User/Kernel depending on where we came from */
+       unsigned long orig_r0;
 
        /*
         * To distinguish bet excp, syscall, irq
@@ -55,13 +55,13 @@ struct pt_regs {
                unsigned long event;
        };
 
-       long user_r25;
+       unsigned long user_r25;
 };
 #else
 
 struct pt_regs {
 
-       long orig_r0;
+       unsigned long orig_r0;
 
        union {
                struct {
@@ -76,26 +76,26 @@ struct pt_regs {
                unsigned long event;
        };
 
-       long bta;       /* bta_l1, bta_l2, erbta */
+       unsigned long bta;      /* bta_l1, bta_l2, erbta */
 
-       long user_r25;
+       unsigned long user_r25;
 
-       long r26;       /* gp */
-       long fp;
-       long sp;        /* user/kernel sp depending on where we came from  */
+       unsigned long r26;      /* gp */
+       unsigned long fp;
+       unsigned long sp;       /* user/kernel sp depending on where we came from  */
 
-       long r12;
+       unsigned long r12;
 
        /*------- Below list auto saved by h/w -----------*/
-       long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
+       unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
 
-       long blink;
-       long lp_end, lp_start, lp_count;
+       unsigned long blink;
+       unsigned long lp_end, lp_start, lp_count;
 
-       long ei, ldi, jli;
+       unsigned long ei, ldi, jli;
 
-       long ret;
-       long status32;
+       unsigned long ret;
+       unsigned long status32;
 };
 
 #endif
@@ -103,7 +103,7 @@ struct pt_regs {
 /* Callee saved registers - need to be saved only when you are scheduled out */
 
 struct callee_regs {
-       long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
+       unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
 };
 
 #define instruction_pointer(regs)      ((regs)->ret)
@@ -142,7 +142,7 @@ struct callee_regs {
 
 static inline long regs_return_value(struct pt_regs *regs)
 {
-       return regs->r0;
+       return (long)regs->r0;
 }
 
 #endif /* !__ASSEMBLY__ */
index e1651df6a93d5bc8ab0af3a833c7c6ffd23acacc..db8c59d1eaeb760798c287a15720573ed58b9e4a 100644 (file)
 #define arch_spin_unlock_wait(x) \
        do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0)
 
+#ifdef CONFIG_ARC_HAS_LLSC
+
+/*
+ * A normal LLOCK/SCOND based system, w/o need for livelock workaround
+ */
+#ifndef CONFIG_ARC_STAR_9000923308
+
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+       unsigned int val;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 1b   \n"     /* spin while LOCKED */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 4f   \n"     /* already LOCKED, just bail */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bnz     1b                      \n"
+       "       mov     %[got_it], 1            \n"
+       "4:                                     \n"
+       "                                       \n"
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       smp_mb();
+
+       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * zero means writer holds the lock exclusively, deny Reader.
+        * Otherwise grant lock to first/subseq reader
+        *
+        *      if (rw->counter > 0) {
+        *              rw->counter--;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 1b\n"     /* <= 0: spin while write locked */
+       "       sub     %[val], %[val], 1       \n"     /* reader lock */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 4f\n"     /* <= 0: already write locked, bail */
+       "       sub     %[val], %[val], 1       \n"     /* counter-- */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"     /* retry if collided with someone */
+       "       mov     %[got_it], 1            \n"
+       "                                       \n"
+       "4: ; --- done ---                      \n"
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+        * deny writer. Otherwise if unlocked grant to writer
+        * Hence the claim that Linux rwlocks are unfair to writers.
+        * (can be starved for an indefinite time by readers).
+        *
+        *      if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+        *              rw->counter = 0;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 1b \n"     /* while !UNLOCKED spin */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 4f \n"     /* !UNLOCKED, bail */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"     /* retry if collided with someone */
+       "       mov     %[got_it], 1            \n"
+       "                                       \n"
+       "4: ; --- done ---                      \n"
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter++;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       add     %[val], %[val], 1       \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter))
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       smp_mb();
+
+       rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+#else  /* CONFIG_ARC_STAR_9000923308 */
+
+/*
+ * HS38x4 could get into a LLOCK/SCOND livelock in case of multiple overlapping
+ * coherency transactions in the SCU. The exclusive line state keeps rotating
+ * among contenting cores leading to a never ending cycle. So break the cycle
+ * by deferring the retry of failed exclusive access (SCOND). The actual delay
+ * needed is function of number of contending cores as well as the unrelated
+ * coherency traffic from other cores. To keep the code simple, start off with
+ * small delay of 1 which would suffice most cases and in case of contention
+ * double the delay. Eventually the delay is sufficient such that the coherency
+ * pipeline is drained, thus a subsequent exclusive access would succeed.
+ */
+
+#define SCOND_FAIL_RETRY_VAR_DEF                                               \
+       unsigned int delay, tmp;                                                \
+
+#define SCOND_FAIL_RETRY_ASM                                                   \
+       "   ; --- scond fail delay ---          \n"                             \
+       "       mov     %[tmp], %[delay]        \n"     /* tmp = delay */       \
+       "2:     brne.d  %[tmp], 0, 2b           \n"     /* while (tmp != 0) */  \
+       "       sub     %[tmp], %[tmp], 1       \n"     /* tmp-- */             \
+       "       rol     %[delay], %[delay]      \n"     /* delay *= 2 */        \
+       "       b       1b                      \n"     /* start over */        \
+       "                                       \n"                             \
+       "4: ; --- done ---                      \n"                             \
+
+#define SCOND_FAIL_RETRY_VARS                                                  \
+         ,[delay] "=&r" (delay), [tmp] "=&r"   (tmp)                           \
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 0b   \n"     /* spin while LOCKED */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bz      4f                      \n"     /* done */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[slock]]      \n"
+       "       breq    %[val], %[LOCKED], 4f   \n"     /* already LOCKED, just bail */
+       "       scond   %[LOCKED], [%[slock]]   \n"     /* acquire */
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [slock]       "r"     (&(lock->slock)),
+         [LOCKED]      "r"     (__ARCH_SPIN_LOCK_LOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       smp_mb();
+
+       lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
+
+       smp_mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ */
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       /*
+        * zero means writer holds the lock exclusively, deny Reader.
+        * Otherwise grant lock to first/subseq reader
+        *
+        *      if (rw->counter > 0) {
+        *              rw->counter--;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 0b\n"     /* <= 0: spin while write locked */
+       "       sub     %[val], %[val], 1       \n"     /* reader lock */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz      4f                      \n"     /* done */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brls    %[val], %[WR_LOCKED], 4f\n"     /* <= 0: already write locked, bail */
+       "       sub     %[val], %[val], 1       \n"     /* counter-- */
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       /*
+        * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+        * deny writer. Otherwise if unlocked grant to writer
+        * Hence the claim that Linux rwlocks are unfair to writers.
+        * (can be starved for an indefinite time by readers).
+        *
+        *      if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+        *              rw->counter = 0;
+        *              ret = 1;
+        *      }
+        */
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 0b \n"     /* while !UNLOCKED spin */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz      4f                      \n"
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       unsigned int val, got_it = 0;
+       SCOND_FAIL_RETRY_VAR_DEF;
+
+       smp_mb();
+
+       __asm__ __volatile__(
+       "0:     mov     %[delay], 1             \n"
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       brne    %[val], %[UNLOCKED], 4f \n"     /* !UNLOCKED, bail */
+       "       mov     %[val], %[WR_LOCKED]    \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bz.d    4f                      \n"
+       "       mov.z   %[got_it], 1            \n"     /* got it */
+       "                                       \n"
+       SCOND_FAIL_RETRY_ASM
+
+       : [val]         "=&r"   (val),
+         [got_it]      "+&r"   (got_it)
+         SCOND_FAIL_RETRY_VARS
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "ir"    (__ARCH_RW_LOCK_UNLOCKED__),
+         [WR_LOCKED]   "ir"    (0)
+       : "memory", "cc");
+
+       smp_mb();
+
+       return got_it;
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter++;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       add     %[val], %[val], 1       \n"
+       "       scond   %[val], [%[rwlock]]     \n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter))
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       unsigned int val;
+
+       smp_mb();
+
+       /*
+        * rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+        */
+       __asm__ __volatile__(
+       "1:     llock   %[val], [%[rwlock]]     \n"
+       "       scond   %[UNLOCKED], [%[rwlock]]\n"
+       "       bnz     1b                      \n"
+       "                                       \n"
+       : [val]         "=&r"   (val)
+       : [rwlock]      "r"     (&(rw->counter)),
+         [UNLOCKED]    "r"     (__ARCH_RW_LOCK_UNLOCKED__)
+       : "memory", "cc");
+
+       smp_mb();
+}
+
+#undef SCOND_FAIL_RETRY_VAR_DEF
+#undef SCOND_FAIL_RETRY_ASM
+#undef SCOND_FAIL_RETRY_VARS
+
+#endif /* CONFIG_ARC_STAR_9000923308 */
+
+#else  /* !CONFIG_ARC_HAS_LLSC */
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
 
        /*
         * This smp_mb() is technically superfluous, we only need the one
@@ -33,7 +542,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        __asm__ __volatile__(
        "1:     ex  %0, [%1]            \n"
        "       breq  %0, %2, 1b        \n"
-       : "+&r" (tmp)
+       : "+&r" (val)
        : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
        : "memory");
 
@@ -48,26 +557,27 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
        smp_mb();
 }
 
+/* 1 - lock taken successfully */
 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__;
+       unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
 
        smp_mb();
 
        __asm__ __volatile__(
        "1:     ex  %0, [%1]            \n"
-       : "+r" (tmp)
+       : "+r" (val)
        : "r"(&(lock->slock))
        : "memory");
 
        smp_mb();
 
-       return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__);
+       return (val == __ARCH_SPIN_LOCK_UNLOCKED__);
 }
 
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
-       unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__;
+       unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__;
 
        /*
         * RELEASE barrier: given the instructions avail on ARCv2, full barrier
@@ -77,7 +587,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
        __asm__ __volatile__(
        "       ex  %0, [%1]            \n"
-       : "+r" (tmp)
+       : "+r" (val)
        : "r"(&(lock->slock))
        : "memory");
 
@@ -90,19 +600,12 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 /*
  * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
  *
  * The spinlock itself is contained in @counter and access to it is
  * serialized with @lock_mutex.
- *
- * Unfair locking as Writers could be starved indefinitely by Reader(s)
  */
 
-/* Would read_trylock() succeed? */
-#define arch_read_can_lock(x)  ((x)->counter > 0)
-
-/* Would write_trylock() succeed? */
-#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
-
 /* 1 - lock taken successfully */
 static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
@@ -173,6 +676,11 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
        arch_spin_unlock(&(rw->lock_mutex));
 }
 
+#endif
+
+#define arch_read_can_lock(x)  ((x)->counter > 0)
+#define arch_write_can_lock(x) ((x)->counter == __ARCH_RW_LOCK_UNLOCKED__)
+
 #define arch_read_lock_flags(lock, flags)      arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags)     arch_write_lock(lock)
 
index 662627ced4f23a966c85feffb9f9d38a4f7df10a..4e1ef5f650c6f2fc74ee1fbb09957d8d23e7b7da 100644 (file)
@@ -26,7 +26,9 @@ typedef struct {
  */
 typedef struct {
        volatile unsigned int   counter;
+#ifndef CONFIG_ARC_HAS_LLSC
        arch_spinlock_t         lock_mutex;
+#endif
 } arch_rwlock_t;
 
 #define __ARCH_RW_LOCK_UNLOCKED__      0x01000000
index 76a7739aab1c5173f397c0f8a5a79c5169489f41..0b3ef63d4a03b3ef2ff119535ee3c020641e1888 100644 (file)
 */
 struct user_regs_struct {
 
-       long pad;
+       unsigned long pad;
        struct {
-               long bta, lp_start, lp_end, lp_count;
-               long status32, ret, blink, fp, gp;
-               long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
-               long sp;
+               unsigned long bta, lp_start, lp_end, lp_count;
+               unsigned long status32, ret, blink, fp, gp;
+               unsigned long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+               unsigned long sp;
        } scratch;
-       long pad2;
+       unsigned long pad2;
        struct {
-               long r25, r24, r23, r22, r21, r20;
-               long r19, r18, r17, r16, r15, r14, r13;
+               unsigned long r25, r24, r23, r22, r21, r20;
+               unsigned long r19, r18, r17, r16, r15, r14, r13;
        } callee;
-       long efa;       /* break pt addr, for break points in delay slots */
-       long stop_pc;   /* give dbg stop_pc after ensuring brkpt trap */
+       unsigned long efa;      /* break pt addr, for break points in delay slots */
+       unsigned long stop_pc;  /* give dbg stop_pc after ensuring brkpt trap */
 };
 #endif /* !__ASSEMBLY__ */
 
index 6208c630abed23a4fe2fd1306d5b31c6ec1d172e..26c15682747960d3b5b1c412f76dff3c2ebc7780 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/of.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip.h>
-#include "../../drivers/irqchip/irqchip.h"
 #include <asm/irq.h>
 
 /*
index fcdddb631766eab0c9a2d3dd3d9b3456c90dfdb4..039fac30b5c1f2fca837c6f9cc11de0e0c56c35d 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/of.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip.h>
-#include "../../drivers/irqchip/irqchip.h"
 #include <asm/irq.h>
 
 /*
index 30284e8de6ffc2af0844468798a5c1002465eb56..2fb86589054de6c0b051325463ebd03236c70299 100644 (file)
@@ -175,7 +175,6 @@ void mcip_init_early_smp(void)
 #include <linux/irqchip.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
-#include "../../drivers/irqchip/irqchip.h"
 
 /*
  * Set the DEST for @cmn_irq to @cpu_mask (1 bit per core)
@@ -218,11 +217,28 @@ static void idu_irq_unmask(struct irq_data *data)
        raw_spin_unlock_irqrestore(&mcip_lock, flags);
 }
 
+#ifdef CONFIG_SMP
 static int
-idu_irq_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool f)
+idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
+                    bool force)
 {
+       unsigned long flags;
+       cpumask_t online;
+
+       /* errout if no online cpu per @cpumask */
+       if (!cpumask_and(&online, cpumask, cpu_online_mask))
+               return -EINVAL;
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+
+       idu_set_dest(data->hwirq, cpumask_bits(&online)[0]);
+       idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR);
+
+       raw_spin_unlock_irqrestore(&mcip_lock, flags);
+
        return IRQ_SET_MASK_OK;
 }
+#endif
 
 static struct irq_chip idu_irq_chip = {
        .name                   = "MCIP IDU Intc",
@@ -330,8 +346,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
                if (!i)
                        idu_first_irq = irq;
 
-               irq_set_handler_data(irq, domain);
-               irq_set_chained_handler(irq, idu_cascade_isr);
+               irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain);
        }
 
        __mcip_cmd(CMD_IDU_ENABLE, 0);
index a3d186211ed367bcf852718682a62f24b555f3de..cabde9dc0696479cc3a4d3074fd526cf89c85182 100644 (file)
@@ -47,6 +47,7 @@ static void read_arc_build_cfg_regs(void)
        struct bcr_perip uncached_space;
        struct bcr_generic bcr;
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
+       unsigned long perip_space;
        FIX_PTR(cpu);
 
        READ_BCR(AUX_IDENTITY, cpu->core);
@@ -56,7 +57,12 @@ static void read_arc_build_cfg_regs(void)
        cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
 
        READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
-       BUG_ON((uncached_space.start << 24) != ARC_UNCACHED_ADDR_SPACE);
+        if (uncached_space.ver < 3)
+               perip_space = uncached_space.start << 24;
+       else
+               perip_space = read_aux_reg(AUX_NON_VOL) & 0xF0000000;
+
+       BUG_ON(perip_space != ARC_UNCACHED_ADDR_SPACE);
 
        READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
 
@@ -142,17 +148,22 @@ static void read_arc_build_cfg_regs(void)
 }
 
 static const struct cpuinfo_data arc_cpu_tbl[] = {
+#ifdef CONFIG_ISA_ARCOMPACT
        { {0x20, "ARC 600"      }, 0x2F},
        { {0x30, "ARC 700"      }, 0x33},
        { {0x34, "ARC 700 R4.10"}, 0x34},
        { {0x35, "ARC 700 R4.11"}, 0x35},
-       { {0x50, "ARC HS38"     }, 0x51},
+#else
+       { {0x50, "ARC HS38 R2.0"}, 0x51},
+       { {0x52, "ARC HS38 R2.1"}, 0x52},
+#endif
        { {0x00, NULL           } }
 };
 
-#define IS_AVAIL1(v, str)      ((v) ? str : "")
-#define IS_USED(cfg)           (IS_ENABLED(cfg) ? "" : "(not used) ")
-#define IS_AVAIL2(v, str, cfg)  IS_AVAIL1(v, str), IS_AVAIL1(v, IS_USED(cfg))
+#define IS_AVAIL1(v, s)                ((v) ? s : "")
+#define IS_USED_RUN(v)         ((v) ? "" : "(not used) ")
+#define IS_USED_CFG(cfg)       IS_USED_RUN(IS_ENABLED(cfg))
+#define IS_AVAIL2(v, s, cfg)   IS_AVAIL1(v, s), IS_AVAIL1(v, IS_USED_CFG(cfg))
 
 static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
 {
@@ -226,7 +237,7 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
                        n += scnprintf(buf + n, len - n, "mpy[opt %d] ", opt);
                }
                n += scnprintf(buf + n, len - n, "%s",
-                              IS_USED(CONFIG_ARC_HAS_HW_MPY));
+                              IS_USED_CFG(CONFIG_ARC_HAS_HW_MPY));
        }
 
        n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
@@ -325,6 +336,10 @@ static void arc_chk_core_config(void)
                pr_warn("CONFIG_ARC_FPU_SAVE_RESTORE needed for working apps\n");
        else if (!cpu->extn.fpu_dp && fpu_enabled)
                panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
+
+       if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
+           !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
+               panic("llock/scond livelock workaround missing\n");
 }
 
 /*
index 3364d2bbc515471bba6478b8b34a417251ffde56..4294761a2b3e7ad3b36f5eca5bc26490e31ed61f 100644 (file)
@@ -203,34 +203,24 @@ static int arc_clkevent_set_next_event(unsigned long delta,
        return 0;
 }
 
-static void arc_clkevent_set_mode(enum clock_event_mode mode,
-                                 struct clock_event_device *dev)
+static int arc_clkevent_set_periodic(struct clock_event_device *dev)
 {
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-                /*
-                 * At X Hz, 1 sec = 1000ms -> X cycles;
-                 *                    10ms -> X / 100 cycles
-                 */
-               arc_timer_event_setup(arc_get_core_freq() / HZ);
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               break;
-       default:
-               break;
-       }
-
-       return;
+       /*
+        * At X Hz, 1 sec = 1000ms -> X cycles;
+        *                    10ms -> X / 100 cycles
+        */
+       arc_timer_event_setup(arc_get_core_freq() / HZ);
+       return 0;
 }
 
 static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
-       .name           = "ARC Timer0",
-       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-       .mode           = CLOCK_EVT_MODE_UNUSED,
-       .rating         = 300,
-       .irq            = TIMER0_IRQ,   /* hardwired, no need for resources */
-       .set_next_event = arc_clkevent_set_next_event,
-       .set_mode       = arc_clkevent_set_mode,
+       .name                   = "ARC Timer0",
+       .features               = CLOCK_EVT_FEAT_ONESHOT |
+                                 CLOCK_EVT_FEAT_PERIODIC,
+       .rating                 = 300,
+       .irq                    = TIMER0_IRQ,   /* hardwired, no need for resources */
+       .set_next_event         = arc_clkevent_set_next_event,
+       .set_state_periodic     = arc_clkevent_set_periodic,
 };
 
 static irqreturn_t timer_irq_handler(int irq, void *dev_id)
@@ -240,7 +230,7 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
         * irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
         */
        struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
-       int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC;
+       int irq_reenable = clockevent_state_periodic(evt);
 
        /*
         * Any write to CTRL reg ACks the interrupt, we rewrite the
index 807f7d61d7a7cf867bca011251729d1164bd3f33..a6f91e88ce36e3ea2a2c95d8eabdceffa48be7fc 100644 (file)
@@ -58,7 +58,6 @@ static void show_callee_regs(struct callee_regs *cregs)
 
 static void print_task_path_n_nm(struct task_struct *tsk, char *buf)
 {
-       struct path path;
        char *path_nm = NULL;
        struct mm_struct *mm;
        struct file *exe_file;
index 1b2b3acfed52df6f1fb0aad58fa834d3d689482d..0cab0b8a57c5665e6686e9bef843fbfa51f141fd 100644 (file)
@@ -206,7 +206,7 @@ unalignedOffby3:
        ld.ab   r6, [r1, 4]
        prefetch [r1, 28]       ;Prefetch the next read location
        ld.ab   r8, [r1,4]
-       prefetch [r3, 32]       ;Prefetch the next write location
+       prefetchw [r3, 32]      ;Prefetch the next write location
 
        SHIFT_1 (r7, r6, 8)
        or      r7, r7, r5
index 92d573c734b5b3d52dec2d8fcf6eb67cc96d16f6..365b183648154c70de1726955b9242e88d3cc60c 100644 (file)
 
 #undef PREALLOC_NOT_AVAIL
 
-#ifdef PREALLOC_NOT_AVAIL
-#define PREWRITE(A,B)  prefetchw [(A),(B)]
-#else
-#define PREWRITE(A,B)  prealloc [(A),(B)]
-#endif
-
 ENTRY(memset)
        prefetchw [r0]          ; Prefetch the write location
        mov.f   0, r2
@@ -51,9 +45,15 @@ ENTRY(memset)
 
 ;;; Convert len to Dwords, unfold x8
        lsr.f   lp_count, lp_count, 6
+
        lpnz    @.Lset64bytes
        ;; LOOP START
-       PREWRITE(r3, 64)        ;Prefetch the next write location
+#ifdef PREALLOC_NOT_AVAIL
+       prefetchw [r3, 64]      ;Prefetch the next write location
+#else
+       prealloc  [r3, 64]
+#endif
+#ifdef CONFIG_ARC_HAS_LL64
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
@@ -62,16 +62,45 @@ ENTRY(memset)
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
+#else
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+#endif
 .Lset64bytes:
 
        lsr.f   lp_count, r2, 5 ;Last remaining  max 124 bytes
        lpnz    .Lset32bytes
        ;; LOOP START
        prefetchw   [r3, 32]    ;Prefetch the next write location
+#ifdef CONFIG_ARC_HAS_LL64
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
        std.ab  r4, [r3, 8]
+#else
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+       st.ab   r4, [r3, 4]
+#endif
 .Lset32bytes:
 
        and.f   lp_count, r2, 0x1F ;Last remaining 31 bytes
index b29d62ed4f7ece64acc41287ded40e3cfb3e186b..1cd6695b6ab50cbbb870ffa969027a50103dba29 100644 (file)
@@ -468,10 +468,18 @@ static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr,
 noinline void slc_op(unsigned long paddr, unsigned long sz, const int op)
 {
 #ifdef CONFIG_ISA_ARCV2
+       /*
+        * SLC is shared between all cores and concurrent aux operations from
+        * multiple cores need to be serialized using a spinlock
+        * A concurrent operation can be silently ignored and/or the old/new
+        * operation can remain incomplete forever (lockup in SLC_CTRL_BUSY loop
+        * below)
+        */
+       static DEFINE_SPINLOCK(lock);
        unsigned long flags;
        unsigned int ctrl;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&lock, flags);
 
        /*
         * The Region Flush operation is specified by CTRL.RGN_OP[11..9]
@@ -504,7 +512,7 @@ noinline void slc_op(unsigned long paddr, unsigned long sz, const int op)
 
        while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
 
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&lock, flags);
 #endif
 }
 
index 74a637a1cfc48b2c5d4f0047a0b25bc51d238e16..57706a9c69489791df22419ec069c1970d1aa634 100644 (file)
@@ -60,8 +60,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 
        /* This is kernel Virtual address (0x7000_0000 based) */
        kvaddr = ioremap_nocache((unsigned long)paddr, size);
-       if (kvaddr != NULL)
-               memset(kvaddr, 0, size);
+       if (kvaddr == NULL)
+               return NULL;
 
        /* This is bus address, platform dependent */
        *dma_handle = (dma_addr_t)paddr;
index 99f7da513a48462031a58815d48428509bad0848..e7769c3ab5f2b7793aff703ca5e926983b45ec29 100644 (file)
@@ -389,6 +389,21 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od)
 
 static void __init axs103_early_init(void)
 {
+       /*
+        * AXS103 configurations for SMP/QUAD configurations share device tree
+        * which defaults to 90 MHz. However recent failures of Quad config
+        * revealed P&R timing violations so clamp it down to safe 50 MHz
+        * Instead of duplicating defconfig/DT for SMP/QUAD, add a small hack
+        *
+        * This hack is really hacky as of now. Fix it properly by getting the
+        * number of cores as return value of platform's early SMP callback
+        */
+#ifdef CONFIG_ARC_MCIP
+       unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F;
+       if (num_cores > 2)
+               arc_set_core_freq(50 * 1000000);
+#endif
+
        switch (arc_get_core_freq()/1000000) {
        case 33:
                axs103_set_freq(1, 1, 1);
index a750c1425c3a64e8a1f2d138b8bc4d9fd2224b8e..1c5021002fe40b06a2e57daad459bf1b4181b822 100644 (file)
@@ -1693,6 +1693,12 @@ config HIGHMEM
 config HIGHPTE
        bool "Allocate 2nd-level pagetables from highmem"
        depends on HIGHMEM
+       help
+         The VM uses one page of physical memory for each page table.
+         For systems with a lot of processes, this can use a lot of
+         precious low memory, eventually leading to low memory being
+         consumed by page tables.  Setting this option will allow
+         user-space 2nd level page tables to reside in high memory.
 
 config HW_PERF_EVENTS
        bool "Enable hardware performance counter support for perf events"
index f1b15797136649872ab20aa87b89cdcf667b9a05..a2e16f940394c301cdcbdaa00bbd8488127867f2 100644 (file)
@@ -1635,7 +1635,7 @@ config PID_IN_CONTEXTIDR
 
 config DEBUG_SET_MODULE_RONX
        bool "Set loadable kernel module data as NX and text as RO"
-       depends on MODULES
+       depends on MODULES && MMU
        ---help---
          This option helps catch unintended modifications to loadable
          kernel module's text and read-only data. It also prevents execution
index 07ab3d203916732337f909ec5f903db4c7bb1294..7451b447cc2d2cb8cc68a9bf59f125f2dd2ce347 100644 (file)
@@ -312,6 +312,9 @@ INSTALL_TARGETS     = zinstall uinstall install
 
 PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
 
+bootpImage uImage: zImage
+zImage: Image
+
 $(BOOT_TARGETS): vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
 
index 901739fcb85a37abba32822463caea432637d274..5c42d259fa68fbf29c98439306badd1d44987ee0 100644 (file)
@@ -80,3 +80,7 @@
                status = "okay";
        };
 };
+
+&rtc {
+       system-power-controller;
+};
index 0d35ab64641c4a4c906dbf471a4e2d06b51651fe..7106114c74647cd2e76499a6f5654ddf5f98f73d 100644 (file)
@@ -74,6 +74,7 @@
        audio_codec: tlv320aic3106@1b {
                compatible = "ti,tlv320aic3106";
                reg = <0x1b>;
+               ai3x-micbias-vg = <0x2>;
        };
 
        accel: lis331dlh@1d {
        ti,audio-routing =
                "Headphone Jack",       "HPLOUT",
                "Headphone Jack",       "HPROUT",
-               "LINE1L",               "Line In";
+               "MIC3L",                "Mic3L Switch";
 };
 
 &mcasp0 {
        regulators {
                dcdc1_reg: regulator@0 {
                        /* VDD_1V8 system supply */
+                       regulator-always-on;
                };
 
                dcdc2_reg: regulator@1 {
                        /* VDD_CORE voltage limits 0.95V - 1.26V with +/-4% tolerance */
                        regulator-name = "vdd_core";
                        regulator-min-microvolt = <925000>;
-                       regulator-max-microvolt = <1325000>;
+                       regulator-max-microvolt = <1150000>;
                        regulator-boot-on;
+                       regulator-always-on;
                };
 
                dcdc3_reg: regulator@2 {
                        /* VDD_MPU voltage limits 0.95V - 1.1V with +/-4% tolerance */
                        regulator-name = "vdd_mpu";
                        regulator-min-microvolt = <925000>;
-                       regulator-max-microvolt = <1150000>;
+                       regulator-max-microvolt = <1325000>;
                        regulator-boot-on;
+                       regulator-always-on;
                };
 
                ldo1_reg: regulator@3 {
                        /* VRTC 1.8V always-on supply */
+                       regulator-name = "vrtc,vdds";
                        regulator-always-on;
                };
 
                ldo2_reg: regulator@4 {
                        /* 3.3V rail */
+                       regulator-name = "vdd_3v3aux";
+                       regulator-always-on;
                };
 
                ldo3_reg: regulator@5 {
                        /* VDD_3V3A 3.3V rail */
+                       regulator-name = "vdd_3v3a";
                        regulator-min-microvolt = <3300000>;
                        regulator-max-microvolt = <3300000>;
                };
 
                ldo4_reg: regulator@6 {
                        /* VDD_3V3B 3.3V rail */
+                       regulator-name = "vdd_3v3b";
+                       regulator-always-on;
                };
        };
 };
index c80a3e23379213f67fa92fa7a5ba62f3b44c01c2..ade28c790f4bf6abfbb17de0aaee768e8f324837 100644 (file)
                        };
                };
 
+               emif: emif@4c000000 {
+                       compatible = "ti,emif-am4372";
+                       reg = <0x4c000000 0x1000000>;
+                       ti,hwmods = "emif";
+               };
+
                edma: edma@49000000 {
                        compatible = "ti,edma3";
                        ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
                                ti,hwmods = "dss_rfbi";
                                clocks = <&disp_clk>;
                                clock-names = "fck";
+                               status = "disabled";
                        };
                };
 
index a42cc377a8625c35168d93cbe4fd06430ed3a6ac..a63bf78191ea5a57093e97f1d1fc95d904695816 100644 (file)
        phy-supply = <&ldousb_reg>;
 };
 
+&usb2_phy2 {
+       phy-supply = <&ldousb_reg>;
+};
+
 &usb1 {
        dr_mode = "host";
        pinctrl-names = "default";
index 5dfd3a44bf82b38c614da737cea42c6498ef6a73..3e21311f9514a65dac7ec6f8de7ff9cc42bac13a 100644 (file)
                        compatible = "sirf,atlas7-ioc";
                        reg = <0x18880000 0x1000>,
                                <0x10E40000 0x1000>;
+
+                       audio_ac97_pmx: audio_ac97@0 {
+                               audio_ac97 {
+                                       groups = "audio_ac97_grp";
+                                       function = "audio_ac97";
+                               };
+                       };
+
+                       audio_func_dbg_pmx: audio_func_dbg@0 {
+                               audio_func_dbg {
+                                       groups = "audio_func_dbg_grp";
+                                       function = "audio_func_dbg";
+                               };
+                       };
+
+                       audio_i2s_pmx: audio_i2s@0 {
+                               audio_i2s {
+                                       groups = "audio_i2s_grp";
+                                       function = "audio_i2s";
+                               };
+                       };
+
+                       audio_i2s_2ch_pmx: audio_i2s_2ch@0 {
+                               audio_i2s_2ch {
+                                       groups = "audio_i2s_2ch_grp";
+                                       function = "audio_i2s_2ch";
+                               };
+                       };
+
+                       audio_i2s_extclk_pmx: audio_i2s_extclk@0 {
+                               audio_i2s_extclk {
+                                       groups = "audio_i2s_extclk_grp";
+                                       function = "audio_i2s_extclk";
+                               };
+                       };
+
+                       audio_uart0_pmx: audio_uart0@0 {
+                               audio_uart0 {
+                                       groups = "audio_uart0_grp";
+                                       function = "audio_uart0";
+                               };
+                       };
+
+                       audio_uart1_pmx: audio_uart1@0 {
+                               audio_uart1 {
+                                       groups = "audio_uart1_grp";
+                                       function = "audio_uart1";
+                               };
+                       };
+
+                       audio_uart2_pmx0: audio_uart2@0 {
+                               audio_uart2_0 {
+                                       groups = "audio_uart2_grp0";
+                                       function = "audio_uart2_m0";
+                               };
+                       };
+
+                       audio_uart2_pmx1: audio_uart2@1 {
+                               audio_uart2_1 {
+                                       groups = "audio_uart2_grp1";
+                                       function = "audio_uart2_m1";
+                               };
+                       };
+
+                       c_can_trnsvr_pmx: c_can_trnsvr@0 {
+                               c_can_trnsvr {
+                                       groups = "c_can_trnsvr_grp";
+                                       function = "c_can_trnsvr";
+                               };
+                       };
+
+                       c0_can_pmx0: c0_can@0 {
+                               c0_can_0 {
+                                       groups = "c0_can_grp0";
+                                       function = "c0_can_m0";
+                               };
+                       };
+
+                       c0_can_pmx1: c0_can@1 {
+                               c0_can_1 {
+                                       groups = "c0_can_grp1";
+                                       function = "c0_can_m1";
+                               };
+                       };
+
+                       c1_can_pmx0: c1_can@0 {
+                               c1_can_0 {
+                                       groups = "c1_can_grp0";
+                                       function = "c1_can_m0";
+                               };
+                       };
+
+                       c1_can_pmx1: c1_can@1 {
+                               c1_can_1 {
+                                       groups = "c1_can_grp1";
+                                       function = "c1_can_m1";
+                               };
+                       };
+
+                       c1_can_pmx2: c1_can@2 {
+                               c1_can_2 {
+                                       groups = "c1_can_grp2";
+                                       function = "c1_can_m2";
+                               };
+                       };
+
+                       ca_audio_lpc_pmx: ca_audio_lpc@0 {
+                               ca_audio_lpc {
+                                       groups = "ca_audio_lpc_grp";
+                                       function = "ca_audio_lpc";
+                               };
+                       };
+
+                       ca_bt_lpc_pmx: ca_bt_lpc@0 {
+                               ca_bt_lpc {
+                                       groups = "ca_bt_lpc_grp";
+                                       function = "ca_bt_lpc";
+                               };
+                       };
+
+                       ca_coex_pmx: ca_coex@0 {
+                               ca_coex {
+                                       groups = "ca_coex_grp";
+                                       function = "ca_coex";
+                               };
+                       };
+
+                       ca_curator_lpc_pmx: ca_curator_lpc@0 {
+                               ca_curator_lpc {
+                                       groups = "ca_curator_lpc_grp";
+                                       function = "ca_curator_lpc";
+                               };
+                       };
+
+                       ca_pcm_debug_pmx: ca_pcm_debug@0 {
+                               ca_pcm_debug {
+                                       groups = "ca_pcm_debug_grp";
+                                       function = "ca_pcm_debug";
+                               };
+                       };
+
+                       ca_pio_pmx: ca_pio@0 {
+                               ca_pio {
+                                       groups = "ca_pio_grp";
+                                       function = "ca_pio";
+                               };
+                       };
+
+                       ca_sdio_debug_pmx: ca_sdio_debug@0 {
+                               ca_sdio_debug {
+                                       groups = "ca_sdio_debug_grp";
+                                       function = "ca_sdio_debug";
+                               };
+                       };
+
+                       ca_spi_pmx: ca_spi@0 {
+                               ca_spi {
+                                       groups = "ca_spi_grp";
+                                       function = "ca_spi";
+                               };
+                       };
+
+                       ca_trb_pmx: ca_trb@0 {
+                               ca_trb {
+                                       groups = "ca_trb_grp";
+                                       function = "ca_trb";
+                               };
+                       };
+
+                       ca_uart_debug_pmx: ca_uart_debug@0 {
+                               ca_uart_debug {
+                                       groups = "ca_uart_debug_grp";
+                                       function = "ca_uart_debug";
+                               };
+                       };
+
+                       clkc_pmx0: clkc@0 {
+                               clkc_0 {
+                                       groups = "clkc_grp0";
+                                       function = "clkc_m0";
+                               };
+                       };
+
+                       clkc_pmx1: clkc@1 {
+                               clkc_1 {
+                                       groups = "clkc_grp1";
+                                       function = "clkc_m1";
+                               };
+                       };
+
+                       gn_gnss_i2c_pmx: gn_gnss_i2c@0 {
+                               gn_gnss_i2c {
+                                       groups = "gn_gnss_i2c_grp";
+                                       function = "gn_gnss_i2c";
+                               };
+                       };
+
+                       gn_gnss_uart_nopause_pmx: gn_gnss_uart_nopause@0 {
+                               gn_gnss_uart_nopause {
+                                       groups = "gn_gnss_uart_nopause_grp";
+                                       function = "gn_gnss_uart_nopause";
+                               };
+                       };
+
+                       gn_gnss_uart_pmx: gn_gnss_uart@0 {
+                               gn_gnss_uart {
+                                       groups = "gn_gnss_uart_grp";
+                                       function = "gn_gnss_uart";
+                               };
+                       };
+
+                       gn_trg_spi_pmx0: gn_trg_spi@0 {
+                               gn_trg_spi_0 {
+                                       groups = "gn_trg_spi_grp0";
+                                       function = "gn_trg_spi_m0";
+                               };
+                       };
+
+                       gn_trg_spi_pmx1: gn_trg_spi@1 {
+                               gn_trg_spi_1 {
+                                       groups = "gn_trg_spi_grp1";
+                                       function = "gn_trg_spi_m1";
+                               };
+                       };
+
+                       cvbs_dbg_pmx: cvbs_dbg@0 {
+                               cvbs_dbg {
+                                       groups = "cvbs_dbg_grp";
+                                       function = "cvbs_dbg";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx0: cvbs_dbg_test@0 {
+                               cvbs_dbg_test_0 {
+                                       groups = "cvbs_dbg_test_grp0";
+                                       function = "cvbs_dbg_test_m0";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx1: cvbs_dbg_test@1 {
+                               cvbs_dbg_test_1 {
+                                       groups = "cvbs_dbg_test_grp1";
+                                       function = "cvbs_dbg_test_m1";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx2: cvbs_dbg_test@2 {
+                               cvbs_dbg_test_2 {
+                                       groups = "cvbs_dbg_test_grp2";
+                                       function = "cvbs_dbg_test_m2";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx3: cvbs_dbg_test@3 {
+                               cvbs_dbg_test_3 {
+                                       groups = "cvbs_dbg_test_grp3";
+                                       function = "cvbs_dbg_test_m3";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx4: cvbs_dbg_test@4 {
+                               cvbs_dbg_test_4 {
+                                       groups = "cvbs_dbg_test_grp4";
+                                       function = "cvbs_dbg_test_m4";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx5: cvbs_dbg_test@5 {
+                               cvbs_dbg_test_5 {
+                                       groups = "cvbs_dbg_test_grp5";
+                                       function = "cvbs_dbg_test_m5";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx6: cvbs_dbg_test@6 {
+                               cvbs_dbg_test_6 {
+                                       groups = "cvbs_dbg_test_grp6";
+                                       function = "cvbs_dbg_test_m6";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx7: cvbs_dbg_test@7 {
+                               cvbs_dbg_test_7 {
+                                       groups = "cvbs_dbg_test_grp7";
+                                       function = "cvbs_dbg_test_m7";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx8: cvbs_dbg_test@8 {
+                               cvbs_dbg_test_8 {
+                                       groups = "cvbs_dbg_test_grp8";
+                                       function = "cvbs_dbg_test_m8";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx9: cvbs_dbg_test@9 {
+                               cvbs_dbg_test_9 {
+                                       groups = "cvbs_dbg_test_grp9";
+                                       function = "cvbs_dbg_test_m9";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx10: cvbs_dbg_test@10 {
+                               cvbs_dbg_test_10 {
+                                       groups = "cvbs_dbg_test_grp10";
+                                       function = "cvbs_dbg_test_m10";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx11: cvbs_dbg_test@11 {
+                               cvbs_dbg_test_11 {
+                                       groups = "cvbs_dbg_test_grp11";
+                                       function = "cvbs_dbg_test_m11";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx12: cvbs_dbg_test@12 {
+                               cvbs_dbg_test_12 {
+                                       groups = "cvbs_dbg_test_grp12";
+                                       function = "cvbs_dbg_test_m12";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx13: cvbs_dbg_test@13 {
+                               cvbs_dbg_test_13 {
+                                       groups = "cvbs_dbg_test_grp13";
+                                       function = "cvbs_dbg_test_m13";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx14: cvbs_dbg_test@14 {
+                               cvbs_dbg_test_14 {
+                                       groups = "cvbs_dbg_test_grp14";
+                                       function = "cvbs_dbg_test_m14";
+                               };
+                       };
+
+                       cvbs_dbg_test_pmx15: cvbs_dbg_test@15 {
+                               cvbs_dbg_test_15 {
+                                       groups = "cvbs_dbg_test_grp15";
+                                       function = "cvbs_dbg_test_m15";
+                               };
+                       };
+
+                       gn_gnss_power_pmx: gn_gnss_power@0 {
+                               gn_gnss_power {
+                                       groups = "gn_gnss_power_grp";
+                                       function = "gn_gnss_power";
+                               };
+                       };
+
+                       gn_gnss_sw_status_pmx: gn_gnss_sw_status@0 {
+                               gn_gnss_sw_status {
+                                       groups = "gn_gnss_sw_status_grp";
+                                       function = "gn_gnss_sw_status";
+                               };
+                       };
+
+                       gn_gnss_eclk_pmx: gn_gnss_eclk@0 {
+                               gn_gnss_eclk {
+                                       groups = "gn_gnss_eclk_grp";
+                                       function = "gn_gnss_eclk";
+                               };
+                       };
+
+                       gn_gnss_irq1_pmx0: gn_gnss_irq1@0 {
+                               gn_gnss_irq1_0 {
+                                       groups = "gn_gnss_irq1_grp0";
+                                       function = "gn_gnss_irq1_m0";
+                               };
+                       };
+
+                       gn_gnss_irq2_pmx0: gn_gnss_irq2@0 {
+                               gn_gnss_irq2_0 {
+                                       groups = "gn_gnss_irq2_grp0";
+                                       function = "gn_gnss_irq2_m0";
+                               };
+                       };
+
+                       gn_gnss_tm_pmx: gn_gnss_tm@0 {
+                               gn_gnss_tm {
+                                       groups = "gn_gnss_tm_grp";
+                                       function = "gn_gnss_tm";
+                               };
+                       };
+
+                       gn_gnss_tsync_pmx: gn_gnss_tsync@0 {
+                               gn_gnss_tsync {
+                                       groups = "gn_gnss_tsync_grp";
+                                       function = "gn_gnss_tsync";
+                               };
+                       };
+
+                       gn_io_gnsssys_sw_cfg_pmx: gn_io_gnsssys_sw_cfg@0 {
+                               gn_io_gnsssys_sw_cfg {
+                                       groups = "gn_io_gnsssys_sw_cfg_grp";
+                                       function = "gn_io_gnsssys_sw_cfg";
+                               };
+                       };
+
+                       gn_trg_pmx0: gn_trg@0 {
+                               gn_trg_0 {
+                                       groups = "gn_trg_grp0";
+                                       function = "gn_trg_m0";
+                               };
+                       };
+
+                       gn_trg_pmx1: gn_trg@1 {
+                               gn_trg_1 {
+                                       groups = "gn_trg_grp1";
+                                       function = "gn_trg_m1";
+                               };
+                       };
+
+                       gn_trg_shutdown_pmx0: gn_trg_shutdown@0 {
+                               gn_trg_shutdown_0 {
+                                       groups = "gn_trg_shutdown_grp0";
+                                       function = "gn_trg_shutdown_m0";
+                               };
+                       };
+
+                       gn_trg_shutdown_pmx1: gn_trg_shutdown@1 {
+                               gn_trg_shutdown_1 {
+                                       groups = "gn_trg_shutdown_grp1";
+                                       function = "gn_trg_shutdown_m1";
+                               };
+                       };
+
+                       gn_trg_shutdown_pmx2: gn_trg_shutdown@2 {
+                               gn_trg_shutdown_2 {
+                                       groups = "gn_trg_shutdown_grp2";
+                                       function = "gn_trg_shutdown_m2";
+                               };
+                       };
+
+                       gn_trg_shutdown_pmx3: gn_trg_shutdown@3 {
+                               gn_trg_shutdown_3 {
+                                       groups = "gn_trg_shutdown_grp3";
+                                       function = "gn_trg_shutdown_m3";
+                               };
+                       };
+
+                       i2c0_pmx: i2c0@0 {
+                               i2c0 {
+                                       groups = "i2c0_grp";
+                                       function = "i2c0";
+                               };
+                       };
+
+                       i2c1_pmx: i2c1@0 {
+                               i2c1 {
+                                       groups = "i2c1_grp";
+                                       function = "i2c1";
+                               };
+                       };
+
+                       jtag_pmx0: jtag@0 {
+                               jtag_0 {
+                                       groups = "jtag_grp0";
+                                       function = "jtag_m0";
+                               };
+                       };
+
+                       ks_kas_spi_pmx0: ks_kas_spi@0 {
+                               ks_kas_spi_0 {
+                                       groups = "ks_kas_spi_grp0";
+                                       function = "ks_kas_spi_m0";
+                               };
+                       };
+
+                       ld_ldd_pmx: ld_ldd@0 {
+                               ld_ldd {
+                                       groups = "ld_ldd_grp";
+                                       function = "ld_ldd";
+                               };
+                       };
+
+                       ld_ldd_16bit_pmx: ld_ldd_16bit@0 {
+                               ld_ldd_16bit {
+                                       groups = "ld_ldd_16bit_grp";
+                                       function = "ld_ldd_16bit";
+                               };
+                       };
+
+                       ld_ldd_fck_pmx: ld_ldd_fck@0 {
+                               ld_ldd_fck {
+                                       groups = "ld_ldd_fck_grp";
+                                       function = "ld_ldd_fck";
+                               };
+                       };
+
+                       ld_ldd_lck_pmx: ld_ldd_lck@0 {
+                               ld_ldd_lck {
+                                       groups = "ld_ldd_lck_grp";
+                                       function = "ld_ldd_lck";
+                               };
+                       };
+
+                       lr_lcdrom_pmx: lr_lcdrom@0 {
+                               lr_lcdrom {
+                                       groups = "lr_lcdrom_grp";
+                                       function = "lr_lcdrom";
+                               };
+                       };
+
+                       lvds_analog_pmx: lvds_analog@0 {
+                               lvds_analog {
+                                       groups = "lvds_analog_grp";
+                                       function = "lvds_analog";
+                               };
+                       };
+
+                       nd_df_pmx: nd_df@0 {
+                               nd_df {
+                                       groups = "nd_df_grp";
+                                       function = "nd_df";
+                               };
+                       };
+
+                       nd_df_nowp_pmx: nd_df_nowp@0 {
+                               nd_df_nowp {
+                                       groups = "nd_df_nowp_grp";
+                                       function = "nd_df_nowp";
+                               };
+                       };
+
+                       ps_pmx: ps@0 {
+                               ps {
+                                       groups = "ps_grp";
+                                       function = "ps";
+                               };
+                       };
+
+                       pwc_core_on_pmx: pwc_core_on@0 {
+                               pwc_core_on {
+                                       groups = "pwc_core_on_grp";
+                                       function = "pwc_core_on";
+                               };
+                       };
+
+                       pwc_ext_on_pmx: pwc_ext_on@0 {
+                               pwc_ext_on {
+                                       groups = "pwc_ext_on_grp";
+                                       function = "pwc_ext_on";
+                               };
+                       };
+
+                       pwc_gpio3_clk_pmx: pwc_gpio3_clk@0 {
+                               pwc_gpio3_clk {
+                                       groups = "pwc_gpio3_clk_grp";
+                                       function = "pwc_gpio3_clk";
+                               };
+                       };
+
+                       pwc_io_on_pmx: pwc_io_on@0 {
+                               pwc_io_on {
+                                       groups = "pwc_io_on_grp";
+                                       function = "pwc_io_on";
+                               };
+                       };
+
+                       pwc_lowbatt_b_pmx0: pwc_lowbatt_b@0 {
+                               pwc_lowbatt_b_0 {
+                                       groups = "pwc_lowbatt_b_grp0";
+                                       function = "pwc_lowbatt_b_m0";
+                               };
+                       };
+
+                       pwc_mem_on_pmx: pwc_mem_on@0 {
+                               pwc_mem_on {
+                                       groups = "pwc_mem_on_grp";
+                                       function = "pwc_mem_on";
+                               };
+                       };
+
+                       pwc_on_key_b_pmx0: pwc_on_key_b@0 {
+                               pwc_on_key_b_0 {
+                                       groups = "pwc_on_key_b_grp0";
+                                       function = "pwc_on_key_b_m0";
+                               };
+                       };
+
+                       pwc_wakeup_src0_pmx: pwc_wakeup_src0@0 {
+                               pwc_wakeup_src0 {
+                                       groups = "pwc_wakeup_src0_grp";
+                                       function = "pwc_wakeup_src0";
+                               };
+                       };
+
+                       pwc_wakeup_src1_pmx: pwc_wakeup_src1@0 {
+                               pwc_wakeup_src1 {
+                                       groups = "pwc_wakeup_src1_grp";
+                                       function = "pwc_wakeup_src1";
+                               };
+                       };
+
+                       pwc_wakeup_src2_pmx: pwc_wakeup_src2@0 {
+                               pwc_wakeup_src2 {
+                                       groups = "pwc_wakeup_src2_grp";
+                                       function = "pwc_wakeup_src2";
+                               };
+                       };
+
+                       pwc_wakeup_src3_pmx: pwc_wakeup_src3@0 {
+                               pwc_wakeup_src3 {
+                                       groups = "pwc_wakeup_src3_grp";
+                                       function = "pwc_wakeup_src3";
+                               };
+                       };
+
+                       pw_cko0_pmx0: pw_cko0@0 {
+                               pw_cko0_0 {
+                                       groups = "pw_cko0_grp0";
+                                       function = "pw_cko0_m0";
+                               };
+                       };
+
+                       pw_cko0_pmx1: pw_cko0@1 {
+                               pw_cko0_1 {
+                                       groups = "pw_cko0_grp1";
+                                       function = "pw_cko0_m1";
+                               };
+                       };
+
+                       pw_cko0_pmx2: pw_cko0@2 {
+                               pw_cko0_2 {
+                                       groups = "pw_cko0_grp2";
+                                       function = "pw_cko0_m2";
+                               };
+                       };
+
+                       pw_cko1_pmx0: pw_cko1@0 {
+                               pw_cko1_0 {
+                                       groups = "pw_cko1_grp0";
+                                       function = "pw_cko1_m0";
+                               };
+                       };
+
+                       pw_cko1_pmx1: pw_cko1@1 {
+                               pw_cko1_1 {
+                                       groups = "pw_cko1_grp1";
+                                       function = "pw_cko1_m1";
+                               };
+                       };
+
+                       pw_i2s01_clk_pmx0: pw_i2s01_clk@0 {
+                               pw_i2s01_clk_0 {
+                                       groups = "pw_i2s01_clk_grp0";
+                                       function = "pw_i2s01_clk_m0";
+                               };
+                       };
+
+                       pw_i2s01_clk_pmx1: pw_i2s01_clk@1 {
+                               pw_i2s01_clk_1 {
+                                       groups = "pw_i2s01_clk_grp1";
+                                       function = "pw_i2s01_clk_m1";
+                               };
+                       };
+
+                       pw_pwm0_pmx: pw_pwm0@0 {
+                               pw_pwm0 {
+                                       groups = "pw_pwm0_grp";
+                                       function = "pw_pwm0";
+                               };
+                       };
+
+                       pw_pwm1_pmx: pw_pwm1@0 {
+                               pw_pwm1 {
+                                       groups = "pw_pwm1_grp";
+                                       function = "pw_pwm1";
+                               };
+                       };
+
+                       pw_pwm2_pmx0: pw_pwm2@0 {
+                               pw_pwm2_0 {
+                                       groups = "pw_pwm2_grp0";
+                                       function = "pw_pwm2_m0";
+                               };
+                       };
+
+                       pw_pwm2_pmx1: pw_pwm2@1 {
+                               pw_pwm2_1 {
+                                       groups = "pw_pwm2_grp1";
+                                       function = "pw_pwm2_m1";
+                               };
+                       };
+
+                       pw_pwm3_pmx0: pw_pwm3@0 {
+                               pw_pwm3_0 {
+                                       groups = "pw_pwm3_grp0";
+                                       function = "pw_pwm3_m0";
+                               };
+                       };
+
+                       pw_pwm3_pmx1: pw_pwm3@1 {
+                               pw_pwm3_1 {
+                                       groups = "pw_pwm3_grp1";
+                                       function = "pw_pwm3_m1";
+                               };
+                       };
+
+                       pw_pwm_cpu_vol_pmx0: pw_pwm_cpu_vol@0 {
+                               pw_pwm_cpu_vol_0 {
+                                       groups = "pw_pwm_cpu_vol_grp0";
+                                       function = "pw_pwm_cpu_vol_m0";
+                               };
+                       };
+
+                       pw_pwm_cpu_vol_pmx1: pw_pwm_cpu_vol@1 {
+                               pw_pwm_cpu_vol_1 {
+                                       groups = "pw_pwm_cpu_vol_grp1";
+                                       function = "pw_pwm_cpu_vol_m1";
+                               };
+                       };
+
+                       pw_backlight_pmx0: pw_backlight@0 {
+                               pw_backlight_0 {
+                                       groups = "pw_backlight_grp0";
+                                       function = "pw_backlight_m0";
+                               };
+                       };
+
+                       pw_backlight_pmx1: pw_backlight@1 {
+                               pw_backlight_1 {
+                                       groups = "pw_backlight_grp1";
+                                       function = "pw_backlight_m1";
+                               };
+                       };
+
+                       rg_eth_mac_pmx: rg_eth_mac@0 {
+                               rg_eth_mac {
+                                       groups = "rg_eth_mac_grp";
+                                       function = "rg_eth_mac";
+                               };
+                       };
+
+                       rg_gmac_phy_intr_n_pmx: rg_gmac_phy_intr_n@0 {
+                               rg_gmac_phy_intr_n {
+                                       groups = "rg_gmac_phy_intr_n_grp";
+                                       function = "rg_gmac_phy_intr_n";
+                               };
+                       };
+
+                       rg_rgmii_mac_pmx: rg_rgmii_mac@0 {
+                               rg_rgmii_mac {
+                                       groups = "rg_rgmii_mac_grp";
+                                       function = "rg_rgmii_mac";
+                               };
+                       };
+
+                       rg_rgmii_phy_ref_clk_pmx0: rg_rgmii_phy_ref_clk@0 {
+                               rg_rgmii_phy_ref_clk_0 {
+                                       groups =
+                                               "rg_rgmii_phy_ref_clk_grp0";
+                                       function =
+                                               "rg_rgmii_phy_ref_clk_m0";
+                               };
+                       };
+
+                       rg_rgmii_phy_ref_clk_pmx1: rg_rgmii_phy_ref_clk@1 {
+                               rg_rgmii_phy_ref_clk_1 {
+                                       groups =
+                                               "rg_rgmii_phy_ref_clk_grp1";
+                                       function =
+                                               "rg_rgmii_phy_ref_clk_m1";
+                               };
+                       };
+
+                       sd0_pmx: sd0@0 {
+                               sd0 {
+                                       groups = "sd0_grp";
+                                       function = "sd0";
+                               };
+                       };
+
+                       sd0_4bit_pmx: sd0_4bit@0 {
+                               sd0_4bit {
+                                       groups = "sd0_4bit_grp";
+                                       function = "sd0_4bit";
+                               };
+                       };
+
+                       sd1_pmx: sd1@0 {
+                               sd1 {
+                                       groups = "sd1_grp";
+                                       function = "sd1";
+                               };
+                       };
+
+                       sd1_4bit_pmx0: sd1_4bit@0 {
+                               sd1_4bit_0 {
+                                       groups = "sd1_4bit_grp0";
+                                       function = "sd1_4bit_m0";
+                               };
+                       };
+
+                       sd1_4bit_pmx1: sd1_4bit@1 {
+                               sd1_4bit_1 {
+                                       groups = "sd1_4bit_grp1";
+                                       function = "sd1_4bit_m1";
+                               };
+                       };
+
+                       sd2_pmx0: sd2@0 {
+                               sd2_0 {
+                                       groups = "sd2_grp0";
+                                       function = "sd2_m0";
+                               };
+                       };
+
+                       sd2_no_cdb_pmx0: sd2_no_cdb@0 {
+                               sd2_no_cdb_0 {
+                                       groups = "sd2_no_cdb_grp0";
+                                       function = "sd2_no_cdb_m0";
+                               };
+                       };
+
+                       sd3_pmx: sd3@0 {
+                               sd3 {
+                                       groups = "sd3_grp";
+                                       function = "sd3";
+                               };
+                       };
+
+                       sd5_pmx: sd5@0 {
+                               sd5 {
+                                       groups = "sd5_grp";
+                                       function = "sd5";
+                               };
+                       };
+
+                       sd6_pmx0: sd6@0 {
+                               sd6_0 {
+                                       groups = "sd6_grp0";
+                                       function = "sd6_m0";
+                               };
+                       };
+
+                       sd6_pmx1: sd6@1 {
+                               sd6_1 {
+                                       groups = "sd6_grp1";
+                                       function = "sd6_m1";
+                               };
+                       };
+
+                       sp0_ext_ldo_on_pmx: sp0_ext_ldo_on@0 {
+                               sp0_ext_ldo_on {
+                                       groups = "sp0_ext_ldo_on_grp";
+                                       function = "sp0_ext_ldo_on";
+                               };
+                       };
+
+                       sp0_qspi_pmx: sp0_qspi@0 {
+                               sp0_qspi {
+                                       groups = "sp0_qspi_grp";
+                                       function = "sp0_qspi";
+                               };
+                       };
+
+                       sp1_spi_pmx: sp1_spi@0 {
+                               sp1_spi {
+                                       groups = "sp1_spi_grp";
+                                       function = "sp1_spi";
+                               };
+                       };
+
+                       tpiu_trace_pmx: tpiu_trace@0 {
+                               tpiu_trace {
+                                       groups = "tpiu_trace_grp";
+                                       function = "tpiu_trace";
+                               };
+                       };
+
+                       uart0_pmx: uart0@0 {
+                               uart0 {
+                                       groups = "uart0_grp";
+                                       function = "uart0";
+                               };
+                       };
+
+                       uart0_nopause_pmx: uart0_nopause@0 {
+                               uart0_nopause {
+                                       groups = "uart0_nopause_grp";
+                                       function = "uart0_nopause";
+                               };
+                       };
+
+                       uart1_pmx: uart1@0 {
+                               uart1 {
+                                       groups = "uart1_grp";
+                                       function = "uart1";
+                               };
+                       };
+
+                       uart2_pmx: uart2@0 {
+                               uart2 {
+                                       groups = "uart2_grp";
+                                       function = "uart2";
+                               };
+                       };
+
+                       uart3_pmx0: uart3@0 {
+                               uart3_0 {
+                                       groups = "uart3_grp0";
+                                       function = "uart3_m0";
+                               };
+                       };
+
+                       uart3_pmx1: uart3@1 {
+                               uart3_1 {
+                                       groups = "uart3_grp1";
+                                       function = "uart3_m1";
+                               };
+                       };
+
+                       uart3_pmx2: uart3@2 {
+                               uart3_2 {
+                                       groups = "uart3_grp2";
+                                       function = "uart3_m2";
+                               };
+                       };
+
+                       uart3_pmx3: uart3@3 {
+                               uart3_3 {
+                                       groups = "uart3_grp3";
+                                       function = "uart3_m3";
+                               };
+                       };
+
+                       uart3_nopause_pmx0: uart3_nopause@0 {
+                               uart3_nopause_0 {
+                                       groups = "uart3_nopause_grp0";
+                                       function = "uart3_nopause_m0";
+                               };
+                       };
+
+                       uart3_nopause_pmx1: uart3_nopause@1 {
+                               uart3_nopause_1 {
+                                       groups = "uart3_nopause_grp1";
+                                       function = "uart3_nopause_m1";
+                               };
+                       };
+
+                       uart4_pmx0: uart4@0 {
+                               uart4_0 {
+                                       groups = "uart4_grp0";
+                                       function = "uart4_m0";
+                               };
+                       };
+
+                       uart4_pmx1: uart4@1 {
+                               uart4_1 {
+                                       groups = "uart4_grp1";
+                                       function = "uart4_m1";
+                               };
+                       };
+
+                       uart4_pmx2: uart4@2 {
+                               uart4_2 {
+                                       groups = "uart4_grp2";
+                                       function = "uart4_m2";
+                               };
+                       };
+
+                       uart4_nopause_pmx: uart4_nopause@0 {
+                               uart4_nopause {
+                                       groups = "uart4_nopause_grp";
+                                       function = "uart4_nopause";
+                               };
+                       };
+
+                       usb0_drvvbus_pmx: usb0_drvvbus@0 {
+                               usb0_drvvbus {
+                                       groups = "usb0_drvvbus_grp";
+                                       function = "usb0_drvvbus";
+                               };
+                       };
+
+                       usb1_drvvbus_pmx: usb1_drvvbus@0 {
+                               usb1_drvvbus {
+                                       groups = "usb1_drvvbus_grp";
+                                       function = "usb1_drvvbus";
+                               };
+                       };
+
+                       visbus_dout_pmx: visbus_dout@0 {
+                               visbus_dout {
+                                       groups = "visbus_dout_grp";
+                                       function = "visbus_dout";
+                               };
+                       };
+
+                       vi_vip1_pmx: vi_vip1@0 {
+                               vi_vip1 {
+                                       groups = "vi_vip1_grp";
+                                       function = "vi_vip1";
+                               };
+                       };
+
+                       vi_vip1_ext_pmx: vi_vip1_ext@0 {
+                               vi_vip1_ext {
+                                       groups = "vi_vip1_ext_grp";
+                                       function = "vi_vip1_ext";
+                               };
+                       };
+
+                       vi_vip1_low8bit_pmx: vi_vip1_low8bit@0 {
+                               vi_vip1_low8bit {
+                                       groups = "vi_vip1_low8bit_grp";
+                                       function = "vi_vip1_low8bit";
+                               };
+                       };
+
+                       vi_vip1_high8bit_pmx: vi_vip1_high8bit@0 {
+                               vi_vip1_high8bit {
+                                       groups = "vi_vip1_high8bit_grp";
+                                       function = "vi_vip1_high8bit";
+                               };
+                       };
                };
 
                pmipc {
                                clock-names = "gpio0_io";
                                gpio-controller;
                                interrupt-controller;
+
+                               gpio-banks = <2>;
+                               gpio-ranges = <&pinctrl 0 0 0>,
+                                               <&pinctrl 32 0 0>;
+                               gpio-ranges-group-names = "lvds_gpio_grp",
+                                                       "uart_nand_gpio_grp";
                        };
 
                        nand@17050000 {
                                #interrupt-cells = <2>;
                                compatible = "sirf,atlas7-gpio";
                                reg = <0x13300000 0x1000>;
-                               interrupts = <0 43 0>, <0 44 0>, <0 45 0>;
+                               interrupts = <0 43 0>, <0 44 0>,
+                                               <0 45 0>, <0 46 0>;
                                clocks = <&car 84>;
                                clock-names = "gpio1_io";
                                gpio-controller;
                                interrupt-controller;
+
+                               gpio-banks = <4>;
+                               gpio-ranges = <&pinctrl 0 0 0>,
+                                               <&pinctrl 32 0 0>,
+                                               <&pinctrl 64 0 0>,
+                                               <&pinctrl 96 0 0>;
+                               gpio-ranges-group-names = "gnss_gpio_grp",
+                                                       "lcd_vip_gpio_grp",
+                                                       "sdio_i2s_gpio_grp",
+                                                       "sp_rgmii_gpio_grp";
                        };
 
                        sd2: sdhci@14200000 {
                                interrupts = <0 47 0>;
                                gpio-controller;
                                interrupt-controller;
+
+                               gpio-banks = <1>;
+                               gpio-ranges = <&pinctrl 0 0 0>;
+                               gpio-ranges-group-names = "rtc_gpio_grp";
                        };
 
                        rtc-iobg@18840000 {
index 9c7fb0acae79c9d3c34f58e1acca360057d0c43e..4e42f30cb318df29a1fad4c9ef8752c769cad137 100644 (file)
@@ -22,6 +22,7 @@
                        MATRIX_KEY(0x00, 0x02, KEY_F1)
                        MATRIX_KEY(0x00, 0x03, KEY_B)
                        MATRIX_KEY(0x00, 0x04, KEY_F10)
+                       MATRIX_KEY(0x00, 0x05, KEY_RO)
                        MATRIX_KEY(0x00, 0x06, KEY_N)
                        MATRIX_KEY(0x00, 0x08, KEY_EQUAL)
                        MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT)
@@ -34,6 +35,7 @@
                        MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE)
                        MATRIX_KEY(0x01, 0x09, KEY_F9)
                        MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE)
+                       MATRIX_KEY(0x01, 0x0c, KEY_HENKAN)
 
                        MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL)
                        MATRIX_KEY(0x02, 0x01, KEY_TAB)
@@ -45,6 +47,7 @@
                        MATRIX_KEY(0x02, 0x07, KEY_102ND)
                        MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE)
                        MATRIX_KEY(0x02, 0x09, KEY_F8)
+                       MATRIX_KEY(0x02, 0x0a, KEY_YEN)
 
                        MATRIX_KEY(0x03, 0x01, KEY_GRAVE)
                        MATRIX_KEY(0x03, 0x02, KEY_F2)
@@ -53,6 +56,7 @@
                        MATRIX_KEY(0x03, 0x06, KEY_6)
                        MATRIX_KEY(0x03, 0x08, KEY_MINUS)
                        MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH)
+                       MATRIX_KEY(0x03, 0x0c, KEY_MUHENKAN)
 
                        MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL)
                        MATRIX_KEY(0x04, 0x01, KEY_A)
index aa465904f6cc420ecad93f006bc5e622d8e70b36..096f68be99e2b962a9b9ee86a22a978509477aad 100644 (file)
 
 &dcan1 {
        status = "ok";
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&dcan1_pins_default>;
+       pinctrl-names = "default", "sleep", "active";
+       pinctrl-0 = <&dcan1_pins_sleep>;
        pinctrl-1 = <&dcan1_pins_sleep>;
+       pinctrl-2 = <&dcan1_pins_default>;
 };
index 8f1e25bcecbd76273f62671e8b9afa8f193ea261..1e29ccf77ea24f56fd16f8960d2b585ccc7ce9fc 100644 (file)
                                ranges = <0 0x2000 0x2000>;
 
                                scm_conf: scm_conf@0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon", "simple-bus";
                                        reg = <0x0 0x1400>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                                ctrl-module = <&omap_control_sata>;
                                clocks = <&sys_clkin1>, <&sata_ref_clk>;
                                clock-names = "sysclk", "refclk";
+                               syscon-pllreset = <&scm_conf 0x3fc>;
                                #phy-cells = <0>;
                        };
 
index 4e1b60581782c43fc40c9b167e45f90e64024068..803738414086a76f80a8e669142b2caaaa400092 100644 (file)
 
 &dcan1 {
        status = "ok";
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&dcan1_pins_default>;
+       pinctrl-names = "default", "sleep", "active";
+       pinctrl-0 = <&dcan1_pins_sleep>;
        pinctrl-1 = <&dcan1_pins_sleep>;
+       pinctrl-2 = <&dcan1_pins_default>;
 };
 
 &qspi {
index d7201333e3bcd181d0a0281b3d214a6b5e92265a..2db99433e17fdad0299b672ae87e49b6444a457e 100644 (file)
 
                mipi_phy: video-phy@10020710 {
                        compatible = "samsung,s5pv210-mipi-video-phy";
-                       reg = <0x10020710 8>;
                        #phy-cells = <1>;
+                       syscon = <&pmu_system_controller>;
                };
 
                pd_cam: cam-power-domain@10023C00 {
index e0abfc3324d11eaed33838be9c04b7f1a167f5fb..e050d85cdacddf24268870988badefca45d75a88 100644 (file)
        };
 };
 
+&cpu0 {
+       cpu0-supply = <&buck1_reg>;
+};
+
 &fimd {
        pinctrl-0 = <&lcd_en &lcd_clk &lcd_data24 &pwm0_out>;
        pinctrl-names = "default";
index 98f3ce65cb9a387a55ee588069bf42b51103317c..ba34886f8b65b6227f82ef93c530603b64910449 100644 (file)
        };
 };
 
+&cpu0 {
+       cpu0-supply = <&varm_breg>;
+};
+
 &dsi_0 {
        vddcore-supply = <&vusb_reg>;
        vddio-supply = <&vmipi_reg>;
index d4f2b11319dd10d4d7b79fa295d55e63baccff9c..775892b2cc6a8d1564f1bf463abaa19df1a859a4 100644 (file)
        };
 };
 
+&cpu0 {
+       cpu0-supply = <&vdd_arm_reg>;
+};
+
 &pinctrl_1 {
        hdmi_hpd: hdmi-hpd {
                samsung,pins = "gpx3-7";
index 10d3c173396e4cb67a2443f2d3e641c264bec168..3e5ba665d20009de0a974c9ceccb283e431b3b54 100644 (file)
                        device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0x900>;
+                       clocks = <&clock CLK_ARM_CLK>;
+                       clock-names = "cpu";
+                       clock-latency = <160000>;
+
+                       operating-points = <
+                               1200000 1250000
+                               1000000 1150000
+                               800000  1075000
+                               500000  975000
+                               400000  975000
+                               200000  950000
+                       >;
                        cooling-min-level = <4>;
                        cooling-max-level = <2>;
                        #cooling-cells = <2>; /* min followed by max */
index c892d58e8dad38252dfcdd13c5f758cdc05aca36..b995333ea22b1315cd3a322e7d840b9a9c653c36 100644 (file)
                                interrupts = <36 37 38 39 40 41 42 43 44>;
                                status = "disabled";
                                clocks = <&clks 26>;
+                               #io-channel-cells = <1>;
                        };
 
                        spdif@80054000 {
index dd45e6971bc35061a3b9d5b4579c6e6697ca9eca..9351296356dcc419ccb2746efa031df01bcb6462 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 #include "imx25.dtsi"
 
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio2 1 0>;
-       wp-gpios = <&gpio2 0 0>;
+       cd-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index bc215e4b75fd52c6e5b2e271b4a9e6265d442205..b69be5c499cfc69f8df1902fffd3d0d73eb47280 100644 (file)
                        };
 
                        gpt1: timer@10003000 {
-                               compatible = "fsl,imx27-gpt", "fsl,imx1-gpt";
+                               compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
                                reg = <0x10003000 0x1000>;
                                interrupts = <26>;
                                clocks = <&clks IMX27_CLK_GPT1_IPG_GATE>,
                        };
 
                        gpt2: timer@10004000 {
-                               compatible = "fsl,imx27-gpt", "fsl,imx1-gpt";
+                               compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
                                reg = <0x10004000 0x1000>;
                                interrupts = <25>;
                                clocks = <&clks IMX27_CLK_GPT2_IPG_GATE>,
                        };
 
                        gpt3: timer@10005000 {
-                               compatible = "fsl,imx27-gpt", "fsl,imx1-gpt";
+                               compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
                                reg = <0x10005000 0x1000>;
                                interrupts = <24>;
                                clocks = <&clks IMX27_CLK_GPT3_IPG_GATE>,
                        };
 
                        gpt4: timer@10019000 {
-                               compatible = "fsl,imx27-gpt", "fsl,imx1-gpt";
+                               compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
                                reg = <0x10019000 0x1000>;
                                interrupts = <4>;
                                clocks = <&clks IMX27_CLK_GPT4_IPG_GATE>,
                        };
 
                        gpt5: timer@1001a000 {
-                               compatible = "fsl,imx27-gpt", "fsl,imx1-gpt";
+                               compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
                                reg = <0x1001a000 0x1000>;
                                interrupts = <3>;
                                clocks = <&clks IMX27_CLK_GPT5_IPG_GATE>,
                        };
 
                        gpt6: timer@1001f000 {
-                               compatible = "fsl,imx27-gpt", "fsl,imx1-gpt";
+                               compatible = "fsl,imx27-gpt", "fsl,imx21-gpt";
                                reg = <0x1001f000 0x1000>;
                                interrupts = <2>;
                                clocks = <&clks IMX27_CLK_GPT6_IPG_GATE>,
index b6478e97d6a7eb8cbb6478470d4a5e10794afaff..e6540b5cfa4cac9c06d354be4fdea73c999cd85b 100644 (file)
                        can1: can@53fe4000 {
                                compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan";
                                reg = <0x53fe4000 0x1000>;
-                               clocks = <&clks 33>;
-                               clock-names = "ipg";
+                               clocks = <&clks 33>, <&clks 33>;
+                               clock-names = "ipg", "per";
                                interrupts = <43>;
                                status = "disabled";
                        };
                        can2: can@53fe8000 {
                                compatible = "fsl,imx35-flexcan", "fsl,p1010-flexcan";
                                reg = <0x53fe8000 0x1000>;
-                               clocks = <&clks 34>;
-                               clock-names = "ipg";
+                               clocks = <&clks 34>, <&clks 34>;
+                               clock-names = "ipg", "per";
                                interrupts = <44>;
                                status = "disabled";
                        };
index 93d3ea12328c50c07cf9d7ab4d09fc952dc5a397..0f3fe29b816ebad2c77d95271e76e089437109b2 100644 (file)
@@ -98,7 +98,7 @@
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 29 GPIO_ACTIVE_LOW>;
        bus-width = <4>;
        status = "okay";
 };
index e9337ad52f59b2159a9419b7d177f2cf6baccfe3..3bc18835fb4bbbe0e388922689a70395bb532cd6 100644 (file)
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio1 1 0>;
-       wp-gpios = <&gpio1 9 0>;
+       cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index d0e0f57eb432e9822b005e986c105fc7949e028b..53f40885c530637c1776dc6172764cf6669f918d 100644 (file)
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio1 1 0>;
-       wp-gpios = <&gpio1 9 0>;
+       cd-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index 181ae5ebf23f64396c8a0b24aa01ef7121c73c87..b0d5542ac829a53b1168c8d8501f5e1fcbd8d167 100644 (file)
 &esdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc3>;
-       cd-gpios = <&gpio3 11 0>;
-       wp-gpios = <&gpio3 12 0>;
+       cd-gpios = <&gpio3 11 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio3 12 GPIO_ACTIVE_HIGH>;
        bus-width = <8>;
        status = "okay";
 };
 &tve {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_vga_sync>;
+       ddc-i2c-bus = <&i2c2>;
        fsl,tve-mode = "vga";
-       fsl,hsync-pin = <4>;
-       fsl,vsync-pin = <6>;
+       fsl,hsync-pin = <7>;    /* IPU DI1 PIN7 via EIM_OE */
+       fsl,vsync-pin = <8>;    /* IPU DI1 PIN8 via EIM_RW */
        status = "okay";
 };
 
index 1d325576bcc04d4a119d96f7c85612f2f4bd62a2..fc89ce1e5763a2b03d5da06b38e6e3896e56dd20 100644 (file)
@@ -41,8 +41,8 @@
 &esdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
-       cd-gpios = <&gpio3 13 0>;
-       wp-gpios = <&gpio4 11 0>;
+       cd-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio4 11 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index 4f1f0e2868bf12816ec93f545a8f592e43e7f64d..e03373a58760ff79c431b40fabbb8b54e1d1039e 100644 (file)
@@ -41,8 +41,8 @@
        pinctrl-0 = <&pinctrl_esdhc2>,
                    <&pinctrl_esdhc2_cdwp>;
        vmmc-supply = <&reg_3p3v>;
-       wp-gpios = <&gpio1 2 0>;
-       cd-gpios = <&gpio1 4 0>;
+       wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        status = "disabled";
 };
 
index 704bd72cbfec823da4145ead1fd6e7dc719d094b..d3e50b22064f28777bbd2a3b60f512d844ff9418 100644 (file)
 };
 
 &esdhc1 {
-       cd-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc1>;
 };
 
 &esdhc2 {
-       cd-gpios = <&gpio3 25 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc2>;
index c17d3ad6dba50213c18a9076ca15c261d6740e77..fc51b87ad2087022e8b8648c71fac18e00abb762 100644 (file)
 &esdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_esdhc2>;
-       cd-gpios = <&gpio3 25 0>;
-       wp-gpios = <&gpio2 19 0>;
+       cd-gpios = <&gpio3 25 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 43cb3fd76be764cdceb08efd949f47866ebe03e9..5111f5170d5343398bab4ec60e548de07f26200b 100644 (file)
 &usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio1 4 0>;
-       wp-gpios = <&gpio1 2 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 0>;
-       wp-gpios = <&gpio7 1 0>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 78df05e9d1ce61ca7d71c0825367cd8cd3757925..d6515f7a56c427bc7a8490f932b78320f942a624 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include "imx6q.dtsi"
 
 / {
 };
 
 &usdhc3 {
-       cd-gpios = <&gpio6 11 0>;
-       wp-gpios = <&gpio6 14 0>;
+       cd-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3
index 703539cf36d3078fa7b179fad58c26f9a72b0069..00bd63e63d0cdd47f4ffa012f572f10323a2d14f 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
 #include "imx6q.dtsi"
 
 / {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <4>;
-       cd-gpios = <&gpio6 11 0>;
+       cd-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index a43abfa21e33b9b596dbab2e82b8e121baebdd00..5645d52850a7eca0f1905f7341935ae82ce99859 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
-       cd-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <4>;
-       cd-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
index e6d9195a1da7bfb98260f0d2ca9bbd0f57de9374..f4d6ae564ead290cd9fc1e02d519573364c47af5 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio4 7 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio4 8 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index 1d85de2befb3ef9c8e1257d33a34721e502e1755..a47a0399a1728da0c1293a8312f30bef082fd349 100644 (file)
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
        no-1-8-v;
        status = "okay";
 };
 &usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
        no-1-8-v;
        status = "okay";
index 59e5d15e3ec4bad9cc664fe0f985502cf39a1375..ff41f83551de6ee72bb6da96b24c3e3ed87d4c58 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio1 4 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 2c253d6d20bd1fec6b71d18347f27ef0126e3f5e..45e7c39e80d584c73ade1523a3e4316e549c76d4 100644 (file)
@@ -1,3 +1,5 @@
+#include <dt-bindings/gpio/gpio.h>
+
 / {
        regulators {
                compatible = "simple-bus";
 &usdhc2 { /* module slot */
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio2 2 0>;
+       cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index b5756c21ea1d55b791b10e6728b573a918ad78e7..4493f6e993301da96edefaac1334372cd18cf4c7 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 86f03c1b147c630c43166aa9d4782da28f333519..a857d1294609a0a0670a7d3f92e446e92185b743 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 4a8d97f477592316c3d9ff86cee4bc1b5c9e887f..1afe3385e2d283b7a9a2da84e37ca595ce04c13f 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 62a82f3eba888f7d16f11e8dc8cac129ae4c2073..6dd0b764e036d1c51cdde3015c1a2cc56178a999 100644 (file)
                &pinctrl_hummingboard_usdhc2
        >;
        vmmc-supply = <&reg_3p3v>;
-       cd-gpios = <&gpio1 4 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index 3af16dfe417be4bb6ec89a2f870e05f1b2df3214..d7fe6672d00cf38141aca0ea88cd807cff4b3cc7 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 0>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
 &usdhc4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
-       cd-gpios = <&gpio2 6 0>;
+       cd-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index 1ce6133b67f5c65fefd2fe85d368ac455b199950..9e6ecd99b472dbcb5ce707048fc4fb4775a25a77 100644 (file)
 &usdhc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
-       cd-gpios = <&gpio1 4 0>;
-       wp-gpios = <&gpio1 2 0>;
+       cd-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
        status = "disabled";
 };
 
         pinctrl-names = "default";
         pinctrl-0 = <&pinctrl_usdhc3
                     &pinctrl_usdhc3_cdwp>;
-        cd-gpios = <&gpio1 27 0>;
-        wp-gpios = <&gpio1 29 0>;
+       cd-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
         status = "disabled";
 };
index 488a640796ac05fa50c4299185fbe71c64ef1a13..3373fd958e95c72b098ed14ea2a3228ba7903ea6 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
        cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
-       wp-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <4>;
        cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
-       wp-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 3b24b12651b2b86ee1a74d5baccca435778ddd3e..e329ca5c3322716e14a9117d7d8e1ca956c89f0b 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc3>;
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
-       cd-gpios = <&gpio6 15 0>;
-       wp-gpios = <&gpio1 13 0>;
+       cd-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index e00c44f6a0df888f6ecb8935ddc99b85e932ee43..782379320517735f7beb62814e0ce1944ecebb18 100644 (file)
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio7 0 0>;
-       wp-gpios = <&gpio7 1 0>;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
 &usdhc4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
-       cd-gpios = <&gpio2 6 0>;
+       cd-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
        vmmc-supply = <&reg_3p3v>;
        status = "okay";
 };
index a626e6dd8022c04defdbc56171147c04027aa48b..944eb81cb2b8c03aa663a1ee7f2bcc6ca664af52 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <8>;
-       cd-gpios = <&gpio2 2 0>;
-       wp-gpios = <&gpio2 3 0>;
+       cd-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
        bus-width = <8>;
-       cd-gpios = <&gpio2 0 0>;
-       wp-gpios = <&gpio2 1 0>;
+       cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index f02b80b41d4fb94d9a5f690d9ddc6d89371e32f6..da08de324e9eb595db45c7cae308327d77bd33a9 100644 (file)
        pinctrl-0 = <&pinctrl_usdhc1>;
        bus-width = <4>;
        no-1-8-v;
-       cd-gpios = <&gpio7 2 0>;
+       cd-gpios = <&gpio7 2 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        status = "okay";
 };
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
        no-1-8-v;
-       cd-gpios = <&gpio7 3 0>;
+       cd-gpios = <&gpio7 3 GPIO_ACTIVE_LOW>;
        fsl,wp-controller;
        status = "okay";
 };
index 5fb091675582e25b84026f5447d0be604f9266ac..9e096d811bedac74d09c6ebf584665ff1ac6fead 100644 (file)
@@ -9,6 +9,8 @@
  *
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
        regulators {
                compatible = "simple-bus";
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio1 2 0>;
+       cd-gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       cd-gpios = <&gpio3 9 0>;
+       cd-gpios = <&gpio3 9 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index e6d13592080d7c701056c2f6a73326aa11e715b5..b57033e8c633187a5f52c367a788f46196967fdc 100644 (file)
                        interrupt-names = "msi";
                        #interrupt-cells = <1>;
                        interrupt-map-mask = <0 0 0 0x7>;
-                       interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
-                                       <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
-                                       <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
-                                       <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-map = <0 0 0 1 &gpc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 2 &gpc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 3 &gpc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+                                       <0 0 0 4 &gpc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&clks IMX6QDL_CLK_PCIE_AXI>,
                                 <&clks IMX6QDL_CLK_LVDS1_GATE>,
                                 <&clks IMX6QDL_CLK_PCIE_REF_125M>;
index 945887d3fdb35a6588155590474479901a45671f..b84dff2e94ea1e4e44c15a054d90e67f9d06bde6 100644 (file)
        pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
        bus-width = <8>;
-       cd-gpios = <&gpio4 7 0>;
-       wp-gpios = <&gpio4 6 0>;
+       cd-gpios = <&gpio4 7 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usdhc2>;
        pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
-       cd-gpios = <&gpio5 0 0>;
-       wp-gpios = <&gpio4 29 0>;
+       cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_usdhc3>;
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
-       cd-gpios = <&gpio3 22 0>;
+       cd-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
index e3c0b63c22056764f93dbecfc2b9500770a6343c..115f3fd78971868ad7025fbb0f46c17c4252e574 100644 (file)
@@ -49,7 +49,7 @@
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
        bus-width = <8>;
-       cd-gpios = <&gpio7 10 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
        keep-power-in-suspend;
        enable-sdio-wakeup;
@@ -61,7 +61,7 @@
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
        bus-width = <8>;
-       cd-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio7 11 GPIO_ACTIVE_LOW>;
        no-1-8-v;
        keep-power-in-suspend;
        enable-sdio-wakup;
index cef04cef3a807f44efdc6a44fb754e0eb4b40b1e..ac88c3467078ec92971324395101b7db785da005 100644 (file)
        pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
        pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
        bus-width = <8>;
-       cd-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>;
        keep-power-in-suspend;
        enable-sdio-wakeup;
 &usdhc4 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc4>;
-       cd-gpios = <&gpio6 21 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&gpio6 21 GPIO_ACTIVE_LOW>;
        wp-gpios = <&gpio6 20 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 4d1a4b977d8492c62085f87ecff7ad29704eb4ad..fdd1d7c9a5cc2608ac047f088f62e394d88db124 100644 (file)
 &usdhc1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc1>;
-       cd-gpios = <&gpio5 0 0>;
-       wp-gpios = <&gpio5 1 0>;
+       cd-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
        enable-sdio-wakeup;
        keep-power-in-suspend;
        status = "okay";
index 4773d6af66a0ad8bfa2296a53737e0d82f3698ce..d56d68fe7ffc65788dee9867630433f263f08293 100644 (file)
@@ -13,9 +13,8 @@ clocks {
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
-               fixed-postdiv = <2>;
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
        };
 
        papllclk: papllclk@2620358 {
index 50e555eab50d98e971014e57ed8611df5a07a007..675fb8e492c6aa0478a6d5df01b30fbe1e281b7d 100644 (file)
@@ -86,7 +86,7 @@
                        gpio,syscon-dev = <&devctrl 0x240>;
                };
 
-               pcie@21020000 {
+               pcie1: pcie@21020000 {
                        compatible = "ti,keystone-pcie","snps,dw-pcie";
                        clocks = <&clkpcie1>;
                        clock-names = "pcie";
@@ -96,6 +96,7 @@
                        ranges = <0x81000000 0 0 0x23260000 0x4000 0x4000
                                0x82000000 0 0x60000000 0x60000000 0 0x10000000>;
 
+                       status = "disabled";
                        device_type = "pci";
                        num-lanes = <2>;
 
                                        <GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
                        };
                };
+
+               mdio: mdio@24200f00 {
+                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x24200f00 0x100>;
+                       status = "disabled";
+                       clocks = <&clkcpgmac>;
+                       clock-names = "fck";
+                       bus_freq        = <2500000>;
+               };
                /include/ "k2e-netcp.dtsi"
        };
 };
-
-&mdio {
-       reg = <0x24200f00 0x100>;
-};
index d5adee3c006758076c4c6a8f693022893b29f4da..af9b7190533aa9c47bf9cd17a63a1d08901ede7d 100644 (file)
@@ -22,9 +22,8 @@ clocks {
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
-               fixed-postdiv = <2>;
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
        };
 
        papllclk: papllclk@2620358 {
index ae6472407b2277012096d733bb80951592555d03..d0810a5f296857394397c7f1c60bffa0011bb6e1 100644 (file)
                        #gpio-cells = <2>;
                        gpio,syscon-dev = <&devctrl 0x25c>;
                };
+
+               mdio: mdio@02090300 {
+                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x02090300 0x100>;
+                       status = "disabled";
+                       clocks = <&clkcpgmac>;
+                       clock-names = "fck";
+                       bus_freq        = <2500000>;
+               };
                /include/ "k2hk-netcp.dtsi"
        };
 };
index eb1e3e29f073856d76a1e47130bdd3639726d648..ef8464bb11ffd9833e24f2dbe4d61d348065dd1c 100644 (file)
@@ -22,9 +22,8 @@ clocks {
                #clock-cells = <0>;
                compatible = "ti,keystone,main-pll-clock";
                clocks = <&refclksys>;
-               reg = <0x02620350 4>, <0x02310110 4>;
-               reg-names = "control", "multiplier";
-               fixed-postdiv = <2>;
+               reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
+               reg-names = "control", "multiplier", "post-divider";
        };
 
        papllclk: papllclk@2620358 {
index 0e007483615e4f097bb747a2d882b2e2d3a030aa..49fd414f680c93ab50cf0dae72d2e9261181da21 100644 (file)
@@ -29,7 +29,6 @@
        };
 
        soc {
-
                /include/ "k2l-clocks.dtsi"
 
                uart2: serial@02348400 {
                        #gpio-cells = <2>;
                        gpio,syscon-dev = <&devctrl 0x24c>;
                };
+
+               mdio: mdio@26200f00 {
+                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0x26200f00 0x100>;
+                       status = "disabled";
+                       clocks = <&clkcpgmac>;
+                       clock-names = "fck";
+                       bus_freq        = <2500000>;
+               };
                /include/ "k2l-netcp.dtsi"
        };
 };
        /* Pin muxed. Enabled and configured by Bootloader */
        status = "disabled";
 };
-
-&mdio {
-       reg = <0x26200f00 0x100>;
-};
index c06542b2c954452dcf891f579014478e573b8221..72816d65f7ec3fcf5d7c47ce792ae57db369754b 100644 (file)
                                  1 0 0x21000A00 0x00000100>;
                };
 
-               mdio: mdio@02090300 {
-                       compatible      = "ti,keystone_mdio", "ti,davinci_mdio";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg             = <0x02090300 0x100>;
-                       status = "disabled";
-                       clocks = <&clkpa>;
-                       clock-names = "fck";
-                       bus_freq        = <2500000>;
-               };
-
                kirq0: keystone_irq@26202a0 {
                        compatible = "ti,keystone-irq";
                        interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
                        ti,syscon-dev = <&devctrl 0x2a0>;
                };
 
-               pcie@21800000 {
+               pcie0: pcie@21800000 {
                        compatible = "ti,keystone-pcie", "snps,dw-pcie";
                        clocks = <&clkpcie>;
                        clock-names = "pcie";
                        ranges = <0x81000000 0 0 0x23250000 0 0x4000
                                0x82000000 0 0x50000000 0x50000000 0 0x10000000>;
 
+                       status = "disabled";
                        device_type = "pci";
                        num-lanes = <2>;
 
index 11a7963be0035a002fa77c2bec6809b34444e584..2390f387c27163bb76e918bb73e26966bee7fb48 100644 (file)
@@ -51,7 +51,8 @@
                                };
 
                                scm_conf: scm_conf@270 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x270 0x240>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
index 233c69e50ae3ba1fc68f6f9f5e17a889c3c434ad..df8908adb0cbf2e0c1784559c181345892d36a85 100644 (file)
 
        lcd0: display@0 {
                compatible = "lgphilips,lb035q02";
-               label = "lcd";
+               label = "lcd35";
 
                reg = <1>;                                      /* CS1 */
                spi-max-frequency = <10000000>;
index f5395b7da912fc64ca79ae0683dabe5a309bcfcf..048fd216970a9acf4627a8edd1f409b61180e2ac 100644 (file)
@@ -98,7 +98,7 @@
 
        lcd0: display@0 {
                compatible = "samsung,lte430wq-f0c", "panel-dpi";
-               label = "lcd";
+               label = "lcd43";
 
                pinctrl-names = "default";
                pinctrl-0 = <&lte430_pins>;
index f884d6adb71e8ed28371afd54c04528403ad29ba..abc4473e6f8a17e51d5e66416be089ab24d7b472 100644 (file)
                                };
 
                                omap4_padconf_global: omap4_padconf_global@5a0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x5a0 0x170>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                        reg = <0x4a066000 0x100>;
                        interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
                        ti,hwmods = "mmu_dsp";
+                       #iommu-cells = <0>;
                };
 
                mmu_ipu: mmu@55082000 {
                        reg = <0x55082000 0x100>;
                        interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
                        ti,hwmods = "mmu_ipu";
+                       #iommu-cells = <0>;
                        ti,iommu-bus-err-back;
                };
 
index 7d24ae0306b56845c80c2c783dd818033a3a6cd1..b1a1263e600168291091a963f9f56aefc87fd59e 100644 (file)
                                };
 
                                omap5_padconf_global: omap5_padconf_global@5a0 {
-                                       compatible = "syscon";
+                                       compatible = "syscon",
+                                                    "simple-bus";
                                        reg = <0x5a0 0xec>;
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                        reg = <0x4a066000 0x100>;
                        interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
                        ti,hwmods = "mmu_dsp";
+                       #iommu-cells = <0>;
                };
 
                mmu_ipu: mmu@55082000 {
                        reg = <0x55082000 0x100>;
                        interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
                        ti,hwmods = "mmu_ipu";
+                       #iommu-cells = <0>;
                        ti,iommu-bus-err-back;
                };
 
index 71468a7eb28f146b3c96c06b955ebb3444a8d033..5e17fd14772884c14dffdffa8d14b9e158d9800d 100644 (file)
        rxc-skew-ps = <2000>;
 };
 
-&mmc0 {
-       vmmc-supply = <&regulator_3_3v>;
-       vqmmc-supply = <&regulator_3_3v>;
-};
-
-&usb1 {
-       status = "okay";
-};
-
 &gpio2 {
        status = "okay";
 };
 
-&i2c1{
+&i2c1 {
        status = "okay";
 
-       accel1: accel1@53{
-               compatible = "adxl34x";
+       accel1: accelerometer@53 {
+               compatible = "adi,adxl345";
                reg = <0x53>;
 
-               interrupt-parent = < &portc >;
+               interrupt-parent = <&portc>;
                interrupts = <3 2>;
        };
 };
+
+&mmc0 {
+       vmmc-supply = <&regulator_3_3v>;
+       vqmmc-supply = <&regulator_3_3v>;
+};
+
+&usb1 {
+       status = "okay";
+};
index d42c84b1df8d02aa4199ac01e68ee547458576d1..e48857249ce7bfc8a9440fa25d80c97460436697 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr1310 Evaluation Baord
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index 9d342920695a5f4e465b04332cebddc9ff73c347..54bc6d3cf2903e8d710aaa0ea178232d3be09942 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for all SPEAr1310 SoCs
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index b23e05ed1d60226d36f3649b3e1a12ee2928c4bd..c611f5606dfea5e2ba37ab5b0b57b7b73e0eed37 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr1340 Evaluation Baord
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index 13e1aa33daa2e379bde1b3cbc2882b1816ba3a39..df2232d767ed2ea7ffca8383e258cecb768dc679 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for all SPEAr1340 SoCs
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index 40accc87e3a252580c1008fa041356a40093620e..14594ce8c18a5a889bbb0fb1fd0c02d7161638c3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for all SPEAr13xx SoCs
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index 5de1431653e4c5a9f4152ce8323b0c111dd80b65..e859e8288bcde7681dad671ec78c7c288c54a731 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr300 Evaluation Baord
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index f79b3dfaabe6c2cc3f984148dde816e1674bc803..f4e92e599729097f195dc6dd368c6628f3196b9c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr300 SoC
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index b09632963d158dfa1f505fc8b0325b5aaa64f42e..070f2c1b78511399c458e2726b6cffb10482c476 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr310 Evaluation Baord
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index 95372080eea60b38f3397cebf52bfb5364900e1c..da210b4547533d1127649233839ad117865bcad2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr310 SoC
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index fdedbb514102b2920a2ea45edcbfa860b28b346e..1b1034477923cfd469b718f83b87e539188eff48 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr320 Evaluation Baord
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index ffea342aeec99575612c38224f05aeaa70594640..22be6e5edaacd845596d2ccd6889a6a3e0944ecd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for SPEAr320 SoC
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index f0e3fcf8e3237e2a63cc7e83579cb5f785efbec5..118135d7589908b424db93f8981587f37c966a72 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DTS file for all SPEAr3xx SoCs
  *
- * Copyright 2012 Viresh Kumar <viresh.linux@gmail.com>
+ * Copyright 2012 Viresh Kumar <vireshk@kernel.org>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
index 32dd55e5f4e6b8567a8a2d207b69311959c9f9a1..6eaaf638e52e217dacf0769cf5c22251754ffc60 100644 (file)
        model = "ST-Ericsson U8540 platform with Device Tree";
        compatible = "st-ericsson,ccu8540", "st-ericsson,u8540";
 
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
+
        memory@0 {
                device_type = "memory";
                reg = <0x20000000 0x1f000000>, <0xc0000000 0x3f000000>;
index 651c56d400a416e4056208b0ddd2b9963aaa2daa..c8b815819cfe3cb6b3268cf700aedfbbfbd4a908 100644 (file)
        model = "ST-Ericsson CCU9540 platform with Device Tree";
        compatible = "st-ericsson,ccu9540", "st-ericsson,u9540";
 
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
+
        memory {
                reg = <0x00000000 0x20000000>;
        };
index 853684ad777337771b48be2982a7c525f95ef1d6..b8f81fb418ce60039ad4e8e04f2892ca34d26bc8 100644 (file)
 #include "skeleton.dtsi"
 
 / {
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               enable-method = "ste,dbx500-smp";
+
+               cpu-map {
+                       cluster0 {
+                               core0 {
+                                       cpu = <&CPU0>;
+                               };
+                               core1 {
+                                       cpu = <&CPU1>;
+                               };
+                       };
+               };
+               CPU0: cpu@300 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <0x300>;
+               };
+               CPU1: cpu@301 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <0x301>;
+               };
+       };
+
        soc {
                #address-cells = <1>;
                #size-cells = <1>;
                interrupt-parent = <&intc>;
                ranges;
 
-               cpus {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
-                       cpu-map {
-                               cluster0 {
-                                       core0 {
-                                               cpu = <&CPU0>;
-                                       };
-                                       core1 {
-                                               cpu = <&CPU1>;
-                                       };
-                               };
-                       };
-                       CPU0: cpu@0 {
-                               device_type = "cpu";
-                               compatible = "arm,cortex-a9";
-                               reg = <0>;
-                       };
-                       CPU1: cpu@1 {
-                               device_type = "cpu";
-                               compatible = "arm,cortex-a9";
-                               reg = <1>;
-                       };
-               };
-
                ptm@801ae000 {
                        compatible = "arm,coresight-etm3x", "arm,primecell";
                        reg = <0x801ae000 0x1000>;
                        power-domains = <&pm_domains DOMAIN_VAPE>;
                };
 
-               uart@80120000 {
+               ux500_serial0: uart@80120000 {
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x80120000 0x1000>;
                        interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               uart@80121000 {
+               ux500_serial1: uart@80121000 {
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x80121000 0x1000>;
                        interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               uart@80007000 {
+               ux500_serial2: uart@80007000 {
                        compatible = "arm,pl011", "arm,primecell";
                        reg = <0x80007000 0x1000>;
                        interrupts = <0 26 IRQ_TYPE_LEVEL_HIGH>;
index 744c1e3a744df1530ba53cd2a56029a9e9ac5d37..6d8ce154347e7a9a78d02e0c06701a02fc02a4ad 100644 (file)
                        status = "okay";
                };
 
+               /* This UART is unused and thus left disabled */
                uart@80121000 {
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&uart1_default_mode>;
                        pinctrl-1 = <&uart1_sleep_mode>;
-                       status = "okay";
                };
 
                uart@80007000 {
index 2b1cb5b584b664033bd5eaba7c7f527ad35c5cf5..18e9795a94f974ccc2522bb7e8c6a0601dde5465 100644 (file)
        model = "ST-Ericsson HREF (pre-v60) and ST UIB";
        compatible = "st-ericsson,mop500", "st-ericsson,u8500";
 
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
+
        soc {
                /* Reset line for the BU21013 touchscreen */
                i2c@80110000 {
index 59523f86681237936420cb3212f69c5b6227a65a..24739914e689edb04ccafb33caeaced14cb6fe63 100644 (file)
 / {
        model = "ST-Ericsson HREF (pre-v60) and TVK1281618 UIB";
        compatible = "st-ericsson,mop500", "st-ericsson,u8500";
+
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
 };
index 7f3975b58d16607d5cf79f10eca8df1dc75ab9d5..b0278f4c486cefa6f3363f91fd3f312bfc87015f 100644 (file)
        };
 
        soc {
+               /* Enable UART1 on this board */
+               uart@80121000 {
+                       status = "okay";
+               };
+
                i2c@80004000 {
                        tps61052@33 {
                                compatible = "tps61052";
index 8c6a2de56cf121305a5f4bde0cf19255a60ff1fe..c2e1ba019a2f6e3d2411a39464e1c9212a2f2ac5 100644 (file)
        model = "ST-Ericsson HREF (v60+) and ST UIB";
        compatible = "st-ericsson,hrefv60+", "st-ericsson,u8500";
 
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
+
        soc {
                /* Reset line for the BU21013 touchscreen */
                i2c@80110000 {
index d53cccdce776b8d9253f9943ee1ad8f427a4a2d3..ebd8547e98f11c181d3d21353660a576355a13fd 100644 (file)
 / {
        model = "ST-Ericsson HREF (v60+) and TVK1281618 UIB";
        compatible = "st-ericsson,hrefv60+", "st-ericsson,u8500";
+
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
 };
index a4bc9e77d640d3762b01952ca23ae07d558cab36..810cda743b6d56ae19118260367f986dcee690af 100644 (file)
                                  <&vaudio_hf_hrefv60_mode>,
                                  <&gbf_hrefv60_mode>,
                                  <&hdtv_hrefv60_mode>,
-                                 <&touch_hrefv60_mode>;
+                                 <&touch_hrefv60_mode>,
+                                 <&gpios_hrefv60_mode>;
 
                        sdi0 {
-                               /* SD card detect GPIO pin, extend default state */
                                sdi0_default_mode: sdi0_default {
+                                       /* SD card detect GPIO pin, extend default state */
                                        default_hrefv60_cfg1 {
                                                pins = "GPIO95_E8";
                                                ste,config = <&gpio_in_pu>;
                                        };
+                                       /* VMMCI level-shifter enable */
+                                       default_hrefv60_cfg2 {
+                                               pins = "GPIO169_D22";
+                                               ste,config = <&gpio_out_lo>;
+                                       };
+                                       /* VMMCI level-shifter voltage select */
+                                       default_hrefv60_cfg3 {
+                                               pins = "GPIO5_AG6";
+                                               ste,config = <&gpio_out_hi>;
+                                       };
                                };
                        };
                        ipgpio {
                                        };
                                };
                        };
+                       gpios {
+                               /* Dangling GPIO pins */
+                               gpios_hrefv60_mode: gpios_hrefv60 {
+                                       default_cfg1 {
+                                               /* Normally UART1 RXD, now dangling */
+                                               pins = "GPIO4_AH6";
+                                               ste,config = <&in_pu>;
+                                       };
+                               };
+                       };
                };
        };
 };
index 3d0b8755caeee62f77ac214d343ab40cebba2ce0..3d25dba143a5d7f4a254460343161ad5e9c4e6ff 100644 (file)
@@ -17,6 +17,7 @@
        };
 
        aliases {
+               serial1 = &uart1;
                stmpe-i2c0 = &stmpe0;
                stmpe-i2c1 = &stmpe1;
        };
index 85d3b95dfdba55b543aa0f66733df936d5074abc..3c140d05f7966c79ae0a0e9ed323baaf2a80adb6 100644 (file)
                bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk";
        };
 
+       aliases {
+               serial1 = &uart1;
+       };
+
        src@101e0000 {
                /* These chrystal drivers are not used on this board */
                disable-sxtalo;
index 9a5f2ba139b7376018d8e48a6263e2ad711fa865..ef794a33b4dcc2ddf2076a0e27ff948e01d67d44 100644 (file)
                        clock-names = "uartclk", "apb_pclk";
                        pinctrl-names = "default";
                        pinctrl-0 = <&uart0_default_mux>;
+                       status = "disabled";
                };
 
                uart1: uart@101fb000 {
index 9edadc37719ffa491aa3ad95c15d27ded3585727..32a5ccb14e7ebfbaec118ceed1f3bc14c2b646df 100644 (file)
        model = "Calao Systems Snowball platform with device tree";
        compatible = "calaosystems,snowball-a9500", "st-ericsson,u9500";
 
+       /* This stablilizes the serial port enumeration */
+       aliases {
+               serial0 = &ux500_serial0;
+               serial1 = &ux500_serial1;
+               serial2 = &ux500_serial2;
+       };
+
        memory {
                reg = <0x00000000 0x20000000>;
        };
                        status = "okay";
                };
 
+               /* This UART is unused and thus left disabled */
                uart@80121000 {
                        pinctrl-names = "default", "sleep";
                        pinctrl-0 = <&uart1_default_mode>;
                        pinctrl-1 = <&uart1_sleep_mode>;
-                       status = "okay";
                };
 
                uart@80007000 {
                                                pins = "GPIO21_AB3"; /* DAT31DIR */
                                                ste,config = <&out_hi>;
                                        };
-
+                                       /* SD card detect GPIO pin, extend default state */
+                                       snowball_cfg2 {
+                                               pins = "GPIO218_AH11";
+                                               ste,config = <&gpio_in_pu>;
+                                       };
+                                       /* VMMCI level-shifter enable */
+                                       snowball_cfg3 {
+                                               pins = "GPIO217_AH12";
+                                               ste,config = <&gpio_out_lo>;
+                                       };
+                                       /* VMMCI level-shifter voltage select */
+                                       snowball_cfg4 {
+                                               pins = "GPIO228_AJ6";
+                                               ste,config = <&gpio_out_hi>;
+                                       };
                                };
                        };
                        ssp0 {
index 107395c32d8265863fecb711311def376ab500b6..17f63f7dfd9ed8f3fbe7d4f6365e19c611700ae7 100644 (file)
                        interface-type = "ace";
                        reg = <0x5000 0x1000>;
                };
+
+               pmu@9000 {
+                        compatible = "arm,cci-400-pmu,r0";
+                        reg = <0x9000 0x5000>;
+                        interrupts = <0 105 4>,
+                                     <0 101 4>,
+                                     <0 102 4>,
+                                     <0 103 4>,
+                                     <0 104 4>;
+               };
        };
 
        memory-controller@7ffd0000 {
                             <1 10 0xf08>;
        };
 
-       pmu {
+       pmu_a15 {
                compatible = "arm,cortex-a15-pmu";
                interrupts = <0 68 4>,
                             <0 69 4>;
-               interrupt-affinity = <&cpu0>, <&cpu1>;
+               interrupt-affinity = <&cpu0>,
+                                    <&cpu1>;
+       };
+
+       pmu_a7 {
+               compatible = "arm,cortex-a7-pmu";
+               interrupts = <0 128 4>,
+                            <0 129 4>,
+                            <0 130 4>;
+               interrupt-affinity = <&cpu2>,
+                                    <&cpu3>,
+                                    <&cpu4>;
        };
 
        oscclk6a: oscclk6a {
index 6d83a1bf0c7494593eb608ddba29f2bfea8d8455..5fd8df6f50ea0c4f9d86cbf0b95364c159c17fb1 100644 (file)
@@ -353,7 +353,6 @@ CONFIG_POWER_RESET_AS3722=y
 CONFIG_POWER_RESET_GPIO=y
 CONFIG_POWER_RESET_GPIO_RESTART=y
 CONFIG_POWER_RESET_KEYSTONE=y
-CONFIG_POWER_RESET_SUN6I=y
 CONFIG_POWER_RESET_RMOBILE=y
 CONFIG_SENSORS_LM90=y
 CONFIG_SENSORS_LM95245=y
index 8ecba00dcd83def3a2ef3abc86d71e1aec942b0f..7ebc346bf9fa56e2dad3ae90914012f0928019b3 100644 (file)
@@ -2,6 +2,7 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PERF_EVENTS=y
+CONFIG_MODULES=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=8
@@ -77,7 +78,6 @@ CONFIG_SPI_SUN6I=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_SUN6I=y
 CONFIG_THERMAL=y
 CONFIG_CPU_THERMAL=y
 CONFIG_WATCHDOG=y
@@ -87,6 +87,10 @@ CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_AXP20X=y
 CONFIG_REGULATOR_GPIO=y
+CONFIG_FB=y
+CONFIG_FB_SIMPLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
index 83c50193626ce03c1a5d590a8d8ff81fa861f180..30b3bc1666d2185b47c0550b920d27a92f43804e 100644 (file)
@@ -13,6 +13,7 @@ generic-y += kdebug.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
index 1c3938f26beba9837d968be7f75d08dfa2b13136..485982084fe96aef7218aeb134527b41f90beb1e 100644 (file)
@@ -140,16 +140,11 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
  * The _caller variety takes a __builtin_return_address(0) value for
  * /proc/vmalloc to use - and should only be used in non-inline functions.
  */
-extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
-       size_t, unsigned int, void *);
 extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
        void *);
-
 extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
 extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
 extern void __iounmap(volatile void __iomem *addr);
-extern void __arm_iounmap(volatile void __iomem *addr);
 
 extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
        unsigned int, void *);
@@ -321,21 +316,24 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
 static inline void memset_io(volatile void __iomem *dst, unsigned c,
        size_t count)
 {
-       memset((void __force *)dst, c, count);
+       extern void mmioset(void *, unsigned int, size_t);
+       mmioset((void __force *)dst, c, count);
 }
 #define memset_io(dst,c,count) memset_io(dst,c,count)
 
 static inline void memcpy_fromio(void *to, const volatile void __iomem *from,
        size_t count)
 {
-       memcpy(to, (const void __force *)from, count);
+       extern void mmiocpy(void *, const void *, size_t);
+       mmiocpy(to, (const void __force *)from, count);
 }
 #define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count)
 
 static inline void memcpy_toio(volatile void __iomem *to, const void *from,
        size_t count)
 {
-       memcpy((void __force *)to, from, count);
+       extern void mmiocpy(void *, const void *, size_t);
+       mmiocpy((void __force *)to, from, count);
 }
 #define memcpy_toio(to,from,count) memcpy_toio(to,from,count)
 
@@ -348,18 +346,61 @@ static inline void memcpy_toio(volatile void __iomem *to, const void *from,
 #endif /* readl */
 
 /*
- * ioremap and friends.
+ * ioremap() and friends.
+ *
+ * ioremap() takes a resource address, and size.  Due to the ARM memory
+ * types, it is important to use the correct ioremap() function as each
+ * mapping has specific properties.
+ *
+ * Function            Memory type     Cacheability    Cache hint
+ * ioremap()           Device          n/a             n/a
+ * ioremap_nocache()   Device          n/a             n/a
+ * ioremap_cache()     Normal          Writeback       Read allocate
+ * ioremap_wc()                Normal          Non-cacheable   n/a
+ * ioremap_wt()                Normal          Non-cacheable   n/a
+ *
+ * All device mappings have the following properties:
+ * - no access speculation
+ * - no repetition (eg, on return from an exception)
+ * - number, order and size of accesses are maintained
+ * - unaligned accesses are "unpredictable"
+ * - writes may be delayed before they hit the endpoint device
  *
- * ioremap takes a PCI memory address, as specified in
- * Documentation/io-mapping.txt.
+ * ioremap_nocache() is the same as ioremap() as there are too many device
+ * drivers using this for device registers, and documentation which tells
+ * people to use it for such for this to be any different.  This is not a
+ * safe fallback for memory-like mappings, or memory regions where the
+ * compiler may generate unaligned accesses - eg, via inlining its own
+ * memcpy.
  *
+ * All normal memory mappings have the following properties:
+ * - reads can be repeated with no side effects
+ * - repeated reads return the last value written
+ * - reads can fetch additional locations without side effects
+ * - writes can be repeated (in certain cases) with no side effects
+ * - writes can be merged before accessing the target
+ * - unaligned accesses can be supported
+ * - ordering is not guaranteed without explicit dependencies or barrier
+ *   instructions
+ * - writes may be delayed before they hit the endpoint memory
+ *
+ * The cache hint is only a performance hint: CPUs may alias these hints.
+ * Eg, a CPU not implementing read allocate but implementing write allocate
+ * will provide a write allocate mapping instead.
  */
-#define ioremap(cookie,size)           __arm_ioremap((cookie), (size), MT_DEVICE)
-#define ioremap_nocache(cookie,size)   __arm_ioremap((cookie), (size), MT_DEVICE)
-#define ioremap_cache(cookie,size)     __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
-#define ioremap_wc(cookie,size)                __arm_ioremap((cookie), (size), MT_DEVICE_WC)
-#define ioremap_wt(cookie,size)                __arm_ioremap((cookie), (size), MT_DEVICE)
-#define iounmap                                __arm_iounmap
+void __iomem *ioremap(resource_size_t res_cookie, size_t size);
+#define ioremap ioremap
+#define ioremap_nocache ioremap
+
+void __iomem *ioremap_cache(resource_size_t res_cookie, size_t size);
+#define ioremap_cache ioremap_cache
+
+void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size);
+#define ioremap_wc ioremap_wc
+#define ioremap_wt ioremap_wc
+
+void iounmap(volatile void __iomem *iomem_cookie);
+#define iounmap iounmap
 
 /*
  * io{read,write}{16,32}be() macros
index 3a72d69b3255e8fa0d53c41ae4df90c126777020..b7f6fb462ea0da21e59e67dbb4e75de729ffdfcc 100644 (file)
@@ -275,7 +275,7 @@ static inline void *phys_to_virt(phys_addr_t x)
  */
 #define __pa(x)                        __virt_to_phys((unsigned long)(x))
 #define __va(x)                        ((void *)__phys_to_virt((phys_addr_t)(x)))
-#define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
+#define pfn_to_kaddr(pfn)      __va((phys_addr_t)(pfn) << PAGE_SHIFT)
 
 extern phys_addr_t (*arch_virt_to_idmap)(unsigned long x);
 
@@ -286,7 +286,7 @@ extern phys_addr_t (*arch_virt_to_idmap)(unsigned long x);
  */
 static inline phys_addr_t __virt_to_idmap(unsigned long x)
 {
-       if (arch_virt_to_idmap)
+       if (IS_ENABLED(CONFIG_MMU) && arch_virt_to_idmap)
                return arch_virt_to_idmap(x);
        else
                return __virt_to_phys(x);
diff --git a/arch/arm/include/asm/mm-arch-hooks.h b/arch/arm/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 7056660..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_ARM_MM_ARCH_HOOKS_H
-#define _ASM_ARM_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_ARM_MM_ARCH_HOOKS_H */
index bfd662e49a25efb04b1929f7dba98a0befe3e684..aeddd28b3595515aa70fb849bd65179a7b800443 100644 (file)
 
 /*
  * These are the memory types, defined to be compatible with
- * pre-ARMv6 CPUs cacheable and bufferable bits:   XXCB
+ * pre-ARMv6 CPUs cacheable and bufferable bits: n/a,n/a,C,B
+ * ARMv6+ without TEX remapping, they are a table index.
+ * ARMv6+ with TEX remapping, they correspond to n/a,TEX(0),C,B
+ *
+ * MT type             Pre-ARMv6       ARMv6+ type / cacheable status
+ * UNCACHED            Uncached        Strongly ordered
+ * BUFFERABLE          Bufferable      Normal memory / non-cacheable
+ * WRITETHROUGH                Writethrough    Normal memory / write through
+ * WRITEBACK           Writeback       Normal memory / write back, read alloc
+ * MINICACHE           Minicache       N/A
+ * WRITEALLOC          Writeback       Normal memory / write back, write alloc
+ * DEV_SHARED          Uncached        Device memory (shared)
+ * DEV_NONSHARED       Uncached        Device memory (non-shared)
+ * DEV_WC              Bufferable      Normal memory / non-cacheable
+ * DEV_CACHED          Writeback       Normal memory / write back, read alloc
+ * VECTORS             Variable        Normal memory / variable
+ *
+ * All normal memory mappings have the following properties:
+ * - reads can be repeated with no side effects
+ * - repeated reads return the last value written
+ * - reads can fetch additional locations without side effects
+ * - writes can be repeated (in certain cases) with no side effects
+ * - writes can be merged before accessing the target
+ * - unaligned accesses can be supported
+ *
+ * All device mappings have the following properties:
+ * - no access speculation
+ * - no repetition (eg, on return from an exception)
+ * - number, order and size of accesses are maintained
+ * - unaligned accesses are "unpredictable"
  */
 #define L_PTE_MT_UNCACHED      (_AT(pteval_t, 0x00) << 2)      /* 0000 */
 #define L_PTE_MT_BUFFERABLE    (_AT(pteval_t, 0x01) << 2)      /* 0001 */
index a88671cfe1ffb1e1ee43b06a7c8c6fd704f38580..5e5a51a99e68ec77b38b8101611bc853eb8496af 100644 (file)
@@ -50,6 +50,9 @@ extern void __aeabi_ulcmp(void);
 
 extern void fpundefinstr(void);
 
+void mmioset(void *, unsigned int, size_t);
+void mmiocpy(void *, const void *, size_t);
+
        /* platform dependent support */
 EXPORT_SYMBOL(arm_delay_ops);
 
@@ -88,6 +91,9 @@ EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(__memzero);
 
+EXPORT_SYMBOL(mmioset);
+EXPORT_SYMBOL(mmiocpy);
+
 #ifdef CONFIG_MMU
 EXPORT_SYMBOL(copy_page);
 
index 7dac3086e361c8e3680d5209e5b72184c9c48cdb..cb4fb1e69778603d41356f3ed7a98695f4cc0cdb 100644 (file)
@@ -410,7 +410,7 @@ ENDPROC(__fiq_abt)
        zero_fp
 
        .if     \trace
-#ifdef CONFIG_IRQSOFF_TRACER
+#ifdef CONFIG_TRACE_IRQFLAGS
        bl      trace_hardirqs_off
 #endif
        ct_user_exit save = 0
index 92828a1dec80c1c33d051d9b76063727598495d5..b48dd4f37f8067e781ee3e135ed7aff27940371f 100644 (file)
@@ -61,6 +61,7 @@ work_pending:
        movlt   scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
        ldmia   sp, {r0 - r6}                   @ have to reload r0 - r6
        b       local_restart                   @ ... and off we go
+ENDPROC(ret_fast_syscall)
 
 /*
  * "slow" syscall return path.  "why" tells us if this was a real syscall.
index bd755d97e459d77ff05cc8a1264f336c58c1b598..29e2991465cb27b579f729deec65e2293a0a04b5 100644 (file)
@@ -399,6 +399,9 @@ ENTRY(secondary_startup)
        sub     lr, r4, r5                      @ mmu has been enabled
        add     r3, r7, lr
        ldrd    r4, [r3, #0]                    @ get secondary_data.pgdir
+ARM_BE8(eor    r4, r4, r5)                     @ Swap r5 and r4 in BE:
+ARM_BE8(eor    r5, r4, r5)                     @ it can be done in 3 steps
+ARM_BE8(eor    r4, r4, r5)                     @ without using a temp reg.
        ldr     r8, [r3, #8]                    @ get secondary_data.swapper_pg_dir
        badr    lr, __enable_mmu                @ return address
        mov     r13, r12                        @ __secondary_switched address
index 357f57ea83f4b82fe0712c7af9a06d677be34d18..54272e0be7137c853f2d684d236449157ef55193 100644 (file)
@@ -818,12 +818,13 @@ static int of_pmu_irq_cfg(struct arm_pmu *pmu)
                        if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
                                break;
 
-               of_node_put(dn);
                if (cpu >= nr_cpu_ids) {
                        pr_warn("Failed to find logical CPU for %s\n",
                                dn->name);
+                       of_node_put(dn);
                        break;
                }
+               of_node_put(dn);
 
                irqs[i] = cpu;
                cpumask_set_cpu(cpu, &pmu->supported_cpus);
index 1a4d232796be67787a305fabb35a1955fe909f94..38269358fd252c6bb93fd58a0478319c436cdfd3 100644 (file)
@@ -50,7 +50,7 @@ static void __soft_restart(void *addr)
        flush_cache_all();
 
        /* Switch to the identity mapping. */
-       phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+       phys_reset = (phys_reset_t)(unsigned long)virt_to_idmap(cpu_reset);
        phys_reset((unsigned long)addr);
 
        /* Should never get here. */
index 90dfbedfbfb8527b74ddcfcef125beb151f875f5..3d6b7821cff8c952e73c72cad5a1f8d90cdf1758 100644 (file)
@@ -578,7 +578,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
 
        if ((unsigned)ipinr < NR_IPI) {
-               trace_ipi_entry(ipi_types[ipinr]);
+               trace_ipi_entry_rcuidle(ipi_types[ipinr]);
                __inc_irq_stat(cpu, ipi_irqs[ipinr]);
        }
 
@@ -637,7 +637,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
        }
 
        if ((unsigned)ipinr < NR_IPI)
-               trace_ipi_exit(ipi_types[ipinr]);
+               trace_ipi_exit_rcuidle(ipi_types[ipinr]);
        set_irq_regs(old_regs);
 }
 
index efe17dd9b9218b7ef16299700a0f2a6d74ca61c1..54a5aeab988d3526657b8e3089942ca8cfe4fe5e 100644 (file)
@@ -296,7 +296,6 @@ static bool tk_is_cntvct(const struct timekeeper *tk)
  */
 void update_vsyscall(struct timekeeper *tk)
 {
-       struct timespec xtime_coarse;
        struct timespec64 *wtm = &tk->wall_to_monotonic;
 
        if (!cntvct_ok) {
@@ -308,10 +307,10 @@ void update_vsyscall(struct timekeeper *tk)
 
        vdso_write_begin(vdso_data);
 
-       xtime_coarse = __current_kernel_time();
        vdso_data->tk_is_cntvct                 = tk_is_cntvct(tk);
-       vdso_data->xtime_coarse_sec             = xtime_coarse.tv_sec;
-       vdso_data->xtime_coarse_nsec            = xtime_coarse.tv_nsec;
+       vdso_data->xtime_coarse_sec             = tk->xtime_sec;
+       vdso_data->xtime_coarse_nsec            = (u32)(tk->tkr_mono.xtime_nsec >>
+                                                       tk->tkr_mono.shift);
        vdso_data->wtm_clock_sec                = wtm->tv_sec;
        vdso_data->wtm_clock_nsec               = wtm->tv_nsec;
 
index 7797e81e40e00f72a85ba90dc5abcc1227504b44..64111bd4440b1aa3702c469ce349b303a0244ebd 100644 (file)
 
 /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
 
+ENTRY(mmiocpy)
 ENTRY(memcpy)
 
 #include "copy_template.S"
 
 ENDPROC(memcpy)
+ENDPROC(mmiocpy)
index a4ee97b5a2bfcfd3099353b44e8678c4df5bff6b..3c65e3bd790fe1f7aec59d9568cb4c0799be0e9a 100644 (file)
@@ -16,6 +16,7 @@
        .text
        .align  5
 
+ENTRY(mmioset)
 ENTRY(memset)
 UNWIND( .fnstart         )
        ands    r3, r0, #3              @ 1 unaligned?
@@ -133,3 +134,4 @@ UNWIND( .fnstart            )
        b       1b
 UNWIND( .fnend   )
 ENDPROC(memset)
+ENDPROC(mmioset)
index 3e58d710013c3ad9b377fc76e6dad58f377e88a7..4b39af2dfda9963345afe18c89131c1056a90b41 100644 (file)
@@ -96,7 +96,7 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
        }
 
        /* the mmap semaphore is taken only if not in an atomic context */
-       atomic = in_atomic();
+       atomic = faulthandler_disabled();
 
        if (!atomic)
                down_read(&current->mm->mmap_sem);
index ddfdd820e6f2b99f6bfa80a51a287255794d74d5..29e08aac8294aa06233b916c130aa0740a6d897f 100644 (file)
@@ -1010,11 +1010,13 @@ static struct davinci_spi_platform_data da8xx_spi_pdata[] = {
                .version        = SPI_VERSION_2,
                .intr_line      = 1,
                .dma_event_q    = EVENTQ_0,
+               .prescaler_limit = 2,
        },
        [1] = {
                .version        = SPI_VERSION_2,
                .intr_line      = 1,
                .dma_event_q    = EVENTQ_0,
+               .prescaler_limit = 2,
        },
 };
 
index 9cbeda798584d236bfbc9db0f6b4abbc2d420b90..567dc56fe8cded405dc05dffb01605cc0316d9dd 100644 (file)
@@ -411,6 +411,7 @@ static struct davinci_spi_platform_data dm355_spi0_pdata = {
        .num_chipselect = 2,
        .cshold_bug     = true,
        .dma_event_q    = EVENTQ_1,
+       .prescaler_limit = 1,
 };
 static struct platform_device dm355_spi0_device = {
        .name = "spi_davinci",
index e3a3c54b6832e4bf35410564411e5235cb54c566..6a890a8486d0032462490144065e8c6e140b8833 100644 (file)
@@ -646,6 +646,7 @@ static struct davinci_spi_platform_data dm365_spi0_pdata = {
        .version        = SPI_VERSION_1,
        .num_chipselect = 2,
        .dma_event_q    = EVENTQ_3,
+       .prescaler_limit = 1,
 };
 
 static struct resource dm365_spi0_resources[] = {
index 6001f1c9d136f45fabd7d61e97638855d0beb46a..4a87e86dec45d1546153ca0ebb7310bbd5f82d93 100644 (file)
@@ -146,9 +146,8 @@ static __init int exynos4_pm_init_power_domain(void)
                pd->base = of_iomap(np, 0);
                if (!pd->base) {
                        pr_warn("%s: failed to map memory\n", __func__);
-                       kfree(pd->pd.name);
+                       kfree_const(pd->pd.name);
                        kfree(pd);
-                       of_node_put(np);
                        continue;
                }
 
index 80bad29d609ac2bf2be07f4de20d3650d8ea28d9..8c4467fad8370c73374ff104209b779e580852e1 100644 (file)
@@ -291,8 +291,6 @@ void __init imx_gpc_check_dt(void)
        }
 }
 
-#ifdef CONFIG_PM_GENERIC_DOMAINS
-
 static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
 {
        int iso, iso2sw;
@@ -399,7 +397,6 @@ static struct genpd_onecell_data imx_gpc_onecell_data = {
 static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
 {
        struct clk *clk;
-       bool is_off;
        int i;
 
        imx6q_pu_domain.reg = pu_reg;
@@ -416,18 +413,13 @@ static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
        }
        imx6q_pu_domain.num_clks = i;
 
-       is_off = IS_ENABLED(CONFIG_PM);
-       if (is_off) {
-               _imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
-       } else {
-               /*
-                * Enable power if compiled without CONFIG_PM in case the
-                * bootloader disabled it.
-                */
-               imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
-       }
+       /* Enable power always in case bootloader disabled it. */
+       imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
+
+       if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
+               return 0;
 
-       pm_genpd_init(&imx6q_pu_domain.base, NULL, is_off);
+       pm_genpd_init(&imx6q_pu_domain.base, NULL, false);
        return of_genpd_add_provider_onecell(dev->of_node,
                                             &imx_gpc_onecell_data);
 
@@ -437,13 +429,6 @@ clk_err:
        return -EINVAL;
 }
 
-#else
-static inline int imx_gpc_genpd_init(struct device *dev, struct regulator *reg)
-{
-       return 0;
-}
-#endif /* CONFIG_PM_GENERIC_DOMAINS */
-
 static int imx_gpc_probe(struct platform_device *pdev)
 {
        struct regulator *pu_reg;
index ecc04ff13e9595213aa57178bb7b0c40183c77c9..4a023e8d1bdb001c01cf361efada2f3ee6944d68 100644 (file)
@@ -60,6 +60,7 @@ config SOC_AM43XX
        select ARM_GIC
        select MACH_OMAP_GENERIC
        select MIGHT_HAVE_CACHE_L2X0
+       select HAVE_ARM_SCU
 
 config SOC_DRA7XX
        bool "TI DRA7XX"
index e1a56d87599e640620e506989de7b5f302c49695..1ed4be184a29b16f6f8d97a082fb80d424ca0665 100644 (file)
@@ -117,7 +117,6 @@ static void omap2_show_dma_caps(void)
        u8 revision = dma_read(REVISION, 0) & 0xff;
        printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
                                revision >> 4, revision & 0xf);
-       return;
 }
 
 static unsigned configure_dma_errata(void)
index 8e52621b5a6bf3ab42ddef8a5c3db79c3391fcf1..e1d2e991d17a31fc15f1c44616c9b4b7f9de3a84 100644 (file)
@@ -392,6 +392,7 @@ static struct irq_chip wakeupgen_chip = {
        .irq_mask               = wakeupgen_mask,
        .irq_unmask             = wakeupgen_unmask,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .irq_set_type           = irq_chip_set_type_parent,
        .flags                  = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
 #ifdef CONFIG_SMP
        .irq_set_affinity       = irq_chip_set_affinity_parent,
index d78c12e7cb5e1ace5f79a9d28f45321e809dea24..486cc4ded1906670c053f110bb09aeee34ea7fa3 100644 (file)
@@ -2373,6 +2373,9 @@ static int of_dev_hwmod_lookup(struct device_node *np,
  * registers.  This address is needed early so the OCP registers that
  * are part of the device's address space can be ioremapped properly.
  *
+ * If SYSC access is not needed, the registers will not be remapped
+ * and non-availability of MPU access is not treated as an error.
+ *
  * Returns 0 on success, -EINVAL if an invalid hwmod is passed, and
  * -ENXIO on absent or invalid register target address space.
  */
@@ -2387,6 +2390,11 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
 
        _save_mpu_port_index(oh);
 
+       /* if we don't need sysc access we don't need to ioremap */
+       if (!oh->class->sysc)
+               return 0;
+
+       /* we can't continue without MPU PORT if we need sysc access */
        if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
                return -ENXIO;
 
@@ -2396,8 +2404,10 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
                         oh->name);
 
                /* Extract the IO space from device tree blob */
-               if (!np)
+               if (!np) {
+                       pr_err("omap_hwmod: %s: no dt node\n", oh->name);
                        return -ENXIO;
+               }
 
                va_start = of_iomap(np, index + oh->mpu_rt_idx);
        } else {
@@ -2456,13 +2466,11 @@ static int __init _init(struct omap_hwmod *oh, void *data)
                                oh->name, np->name);
        }
 
-       if (oh->class->sysc) {
-               r = _init_mpu_rt_base(oh, NULL, index, np);
-               if (r < 0) {
-                       WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
-                            oh->name);
-                       return 0;
-               }
+       r = _init_mpu_rt_base(oh, NULL, index, np);
+       if (r < 0) {
+               WARN(1, "omap_hwmod: %s: doesn't have mpu register target base\n",
+                    oh->name);
+               return 0;
        }
 
        r = _init_clocks(oh, NULL);
index 2606c6608bd8b5c72793cbcc11acc1e2ccee4301..562247bced496bc085f75cb65f5061f8ec2be6c1 100644 (file)
@@ -827,8 +827,7 @@ static struct omap_hwmod_class_sysconfig dra7xx_gpmc_sysc = {
        .syss_offs      = 0x0014,
        .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
                           SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
        .sysc_fields    = &omap_hwmod_sysc_type1,
 };
 
@@ -844,7 +843,7 @@ static struct omap_hwmod dra7xx_gpmc_hwmod = {
        .class          = &dra7xx_gpmc_hwmod_class,
        .clkdm_name     = "l3main1_clkdm",
        /* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
-       .flags          = HWMOD_SWSUP_SIDLE | DEBUG_OMAP_GPMC_HWMOD_FLAGS,
+       .flags          = DEBUG_OMAP_GPMC_HWMOD_FLAGS,
        .main_clk       = "l3_iclk_div",
        .prcm = {
                .omap4 = {
index e03d8b5c9ad0aa174b46c2e54cf2ade518d4cfdc..9ab8932403e5dede46f37dabfd5d8658b01a405e 100644 (file)
@@ -4,6 +4,7 @@ menuconfig ARCH_SIRF
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_IRQ_CHIP
        select NO_IOPORT_MAP
+       select REGMAP
        select PINCTRL
        select PINCTRL_SIRF
        help
index 8f66d8f7ca75e5d12ccbfb14b5f632918b722edb..d4852d24dc7d44010c400ba9425847f96c81eee8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * RTC I/O Bridge interfaces for CSR SiRFprimaII
+ * RTC I/O Bridge interfaces for CSR SiRFprimaII/atlas7
  * ARM access the registers of SYSRTC, GPSRTC and PWRC through this module
  *
  * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/regmap.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
@@ -66,6 +67,7 @@ u32 sirfsoc_rtc_iobrg_readl(u32 addr)
 {
        unsigned long flags, val;
 
+       /* TODO: add hwspinlock to sync with M3 */
        spin_lock_irqsave(&rtciobrg_lock, flags);
 
        val = __sirfsoc_rtc_iobrg_readl(addr);
@@ -90,6 +92,7 @@ void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr)
 {
        unsigned long flags;
 
+        /* TODO: add hwspinlock to sync with M3 */
        spin_lock_irqsave(&rtciobrg_lock, flags);
 
        sirfsoc_rtc_iobrg_pre_writel(val, addr);
@@ -102,6 +105,45 @@ void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr)
 }
 EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel);
 
+
+static int regmap_iobg_regwrite(void *context, unsigned int reg,
+                                  unsigned int val)
+{
+       sirfsoc_rtc_iobrg_writel(val, reg);
+       return 0;
+}
+
+static int regmap_iobg_regread(void *context, unsigned int reg,
+                                 unsigned int *val)
+{
+       *val = (u32)sirfsoc_rtc_iobrg_readl(reg);
+       return 0;
+}
+
+static struct regmap_bus regmap_iobg = {
+       .reg_write = regmap_iobg_regwrite,
+       .reg_read = regmap_iobg_regread,
+};
+
+/**
+ * devm_regmap_init_iobg(): Initialise managed register map
+ *
+ * @iobg: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_iobg(struct device *dev,
+                                   const struct regmap_config *config)
+{
+       const struct regmap_bus *bus = &regmap_iobg;
+
+       return devm_regmap_init(dev, bus, dev, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_iobg);
+
 static const struct of_device_id rtciobrg_ids[] = {
        { .compatible = "sirf,prima2-rtciobg" },
        {}
@@ -132,7 +174,7 @@ static int __init sirfsoc_rtciobrg_init(void)
 }
 postcore_initcall(sirfsoc_rtciobrg_init);
 
-MODULE_AUTHOR("Zhiwu Song <zhiwu.song@csr.com>, "
-               "Barry Song <baohua.song@csr.com>");
+MODULE_AUTHOR("Zhiwu Song <zhiwu.song@csr.com>");
+MODULE_AUTHOR("Barry Song <baohua.song@csr.com>");
 MODULE_DESCRIPTION("CSR SiRFprimaII rtc io bridge");
 MODULE_LICENSE("GPL v2");
index c092730749b9d13228bad861535b2fa98804ac84..bf366b39fa611d8b03028c3f7129c2b3ef7f9c5e 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/ata_platform.h>
 #include <linux/serial_8250.h>
 #include <linux/gpio.h>
+#include <linux/regulator/machine.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -144,6 +145,8 @@ static void __init capc7117_init(void)
 
        capc7117_uarts_init();
        capc7117_ide_init();
+
+       regulator_has_full_constraints();
 }
 
 MACHINE_START(CAPC7117,
index bb99f59a36d880f8879824af44b67c924078b283..a17a91eb8e9a384aae47458ae9e84665aa8e60df 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
+#include <linux/regulator/machine.h>
 
 #include <linux/dm9000.h>
 #include <linux/leds.h>
@@ -466,6 +467,8 @@ static void __init cmx2xx_init(void)
        cmx2xx_init_ac97();
        cmx2xx_init_touchscreen();
        cmx2xx_init_leds();
+
+       regulator_has_full_constraints();
 }
 
 static void __init cmx2xx_init_irq(void)
index 4d3588d26c2a18854b6fc81430dafe371a6af747..5851f4c254c1618cc4a8e433491b3e08e8e5448b 100644 (file)
@@ -835,6 +835,8 @@ static void __init cm_x300_init(void)
        cm_x300_init_ac97();
        cm_x300_init_wi2wi();
        cm_x300_init_bl();
+
+       regulator_has_full_constraints();
 }
 
 static void __init cm_x300_fixup(struct tag *tags, char **cmdline)
index 5f9d9303b346d6c381132a9f8b5664200ed6c6ed..3503826333c74809c9276f022722ce4b4f0a888e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
 #include <linux/ucb1400.h>
 
 #include <asm/mach/arch.h>
@@ -294,6 +295,8 @@ static void __init colibri_pxa270_init(void)
                printk(KERN_ERR "Illegal colibri_pxa270_baseboard type %d\n",
                                colibri_pxa270_baseboard);
        }
+
+       regulator_has_full_constraints();
 }
 
 /* The "Income s.r.o. SH-Dmaster PXA270 SBC" board can be booted either
index 51531ecffca85783fa7cbd1ab608f9f52daa3846..9d7072b040458ff741ed8d30ccddaf9593fb1bd3 100644 (file)
@@ -1306,6 +1306,8 @@ static void __init em_x270_init(void)
        em_x270_init_i2c();
        em_x270_init_camera();
        em_x270_userspace_consumers_init();
+
+       regulator_has_full_constraints();
 }
 
 MACHINE_START(EM_X270, "Compulab EM-X270")
index c98511c5abd10003818c0950841c3f7a4d0a3fd4..9b0eb0252af6facf54158a70d97712a92373c1af 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/can/platform/mcp251x.h>
+#include <linux/regulator/machine.h>
 
 #include "generic.h"
 
@@ -185,6 +186,8 @@ static void __init icontrol_init(void)
        mxm_8x10_mmc_init();
 
        icontrol_can_init();
+
+       regulator_has_full_constraints();
 }
 
 MACHINE_START(ICONTROL, "iControl/SafeTcam boards using Embedian MXM-8x10 CoM")
index 872dcb20e75784710000bb7d409407be269e2bd3..066e3a250ee039bb4e9b72324a06eb4cafb12fbb 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/dm9000.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
+#include <linux/regulator/machine.h>
 #include <linux/i2c/pxa-i2c.h>
 
 #include <asm/types.h>
@@ -534,6 +535,8 @@ static void __init trizeps4_init(void)
 
        BCR_writew(trizeps_conxs_bcr);
        board_backlight_power(1);
+
+       regulator_has_full_constraints();
 }
 
 static void __init trizeps4_map_io(void)
index aa89488f961ecfe9a1ae2cd27083b0284102987c..54122a983ae37664efaf21c6ee4e962412c024cb 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/dm9000.h>
 #include <linux/ucb1400.h>
 #include <linux/ata_platform.h>
+#include <linux/regulator/machine.h>
 #include <linux/regulator/max1586.h>
 #include <linux/i2c/pxa-i2c.h>
 
@@ -711,6 +712,8 @@ static void __init vpac270_init(void)
        vpac270_ts_init();
        vpac270_rtc_init();
        vpac270_ide_init();
+
+       regulator_has_full_constraints();
 }
 
 MACHINE_START(VPAC270, "Voipac PXA270")
index ac2ae5c71ab45b7428440ee8925b121533ba9509..6158566fa0f7421bab2bd1b832fee5ca18b16a3a 100644 (file)
@@ -868,6 +868,8 @@ static void __init zeus_init(void)
        i2c_register_board_info(0, ARRAY_AND_SIZE(zeus_i2c_devices));
        pxa2xx_set_spi_info(3, &pxa2xx_spi_ssp3_master_info);
        spi_register_board_info(zeus_spi_board_info, ARRAY_SIZE(zeus_spi_board_info));
+
+       regulator_has_full_constraints();
 }
 
 static struct map_desc zeus_io_desc[] __initdata = {
index a99d90a4d09c522d0d01c5fd54d5dd2b3c1cdfda..06640914d9a08c79da2d04eb1d42d10577ec9798 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2009-2012 ST Microelectronics
  * Rajeev Kumar <rajeev-dlh.kumar@st.com>
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 92da0a8c6bce6764cb7aebc1cdd07da7d8360ee0..7058720c5278a6d3809a8635cfffe3710219b102 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2009-2012 ST Microelectronics
  * Rajeev Kumar <rajeev-dlh.kumar@st.com>
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 935639ce59ba0e5e21da5d2b01b71751c81a254f..cfaf7c665b5881aedd5d83d09e22df41a0406545 100644 (file)
@@ -4,7 +4,7 @@
  * Miscellaneous registers definitions for SPEAr3xx machine family
  *
  * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index f2d6a01765754b2bce876b41748eb8fe14f6f1bf..5ed841ccf8a38c4dc6db294d0eb90323b88b6e8f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2009,2012 ST Microelectronics
  * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 51b2dc93e4dadfd22a5d6a225bcf70b846febc4b..8439b9c12edb616834a6eeb74274e22e7d02ed04 100644 (file)
@@ -4,7 +4,7 @@
  * Serial port stubs for kernel decompress status messages
  *
  * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index cfa1199d0f4a86152fddfae9f83d3074c330e3a8..b4529f3e0ee976b784e59fdd5ff2d45f64283cbf 100644 (file)
@@ -4,7 +4,7 @@
  * DMAC pl080 definitions for SPEAr platform
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index eb6590ded40dfdaec09b08a7eaf415b4211733ee..608dec6725aea4189dc2486926d96fff3869c0b8 100644 (file)
@@ -4,7 +4,7 @@
  * DMAC pl080 definitions for SPEAr platform
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index ce5e098c48889347227d876fd181023babc1e31b..b4342155a7833eb350cf668a1ce645f20a7b091e 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr platform specific restart functions
  *
  * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index d9ce4d8000f092eb005b2624f87b467a69c996b4..cd5d375d91f0054a6c55926ae8582503a251e908 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr1310 machine source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 3f3c0f124bd384fb7f00860e404f8df77c6c6392..94594d5a446c0f23e1f995487fc2a99d06f24f6a 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr1340 machine source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 2e463a93468d2da133f4f311cd935946eb79e585..b7afce6795f436e9259e84d34f01fa246173eedf 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr13XX machines common source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index b52e48f342f444f319ad51429c6ce38ab9e6db26..5b32edda22769b7f3b76fe5bc16143b3917666aa 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr300 machine source file
  *
  * Copyright (C) 2009-2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index ed2029db391f6071cb69b8bb0d5099193a9b805a..86a44ac7ff67b6b404d69a11172a3a8b21f8be24 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr310 machine source file
  *
  * Copyright (C) 2009-2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index bf634b32a930c2d8b6eb54749a4e3a0c39f5e995..d45d751926c50e344cf168002eecb185eb82a511 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr320 machine source file
  *
  * Copyright (C) 2009-2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index bf3b1fd8cb2398b62e6990c3f116749c76f375ec..23394ac76cf22886e40cb5ec1e098586a43a774d 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr3XX machines common source file
  *
  * Copyright (C) 2009-2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 81502b90dd9130240bd716d4bfb866b9d5ac5efe..4efe2d43a126b4ca13c42aa08fc67ce11c898d35 100644 (file)
@@ -35,7 +35,7 @@ config MACH_SUN7I
        select SUN5I_HSTIMER
 
 config MACH_SUN8I
-       bool "Allwinner A23 (sun8i) SoCs support"
+       bool "Allwinner sun8i Family SoCs support"
        default ARCH_SUNXI
        select ARM_GIC
        select MFD_SUN6I_PRCM
index 1bc811a74a9f4b23c5b78822c5ad6e19a432857b..65bab2876343aff24707105f0432c90faaf90e60 100644 (file)
@@ -67,10 +67,13 @@ MACHINE_END
 
 static const char * const sun8i_board_dt_compat[] = {
        "allwinner,sun8i-a23",
+       "allwinner,sun8i-a33",
+       "allwinner,sun8i-h3",
        NULL,
 };
 
-DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
+DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i Family")
+       .init_time      = sun6i_timer_init,
        .dt_compat      = sun8i_board_dt_compat,
        .init_late      = sunxi_dt_cpufreq_init,
 MACHINE_END
index 1ced8a0f7a52624cae84203eb0d3417aed5171db..cba12f34ff774ca08216c5d2b6061b07b68b1a99 100644 (file)
@@ -1971,7 +1971,7 @@ static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
 {
        int next_bitmap;
 
-       if (mapping->nr_bitmaps > mapping->extensions)
+       if (mapping->nr_bitmaps >= mapping->extensions)
                return -EINVAL;
 
        next_bitmap = mapping->nr_bitmaps;
index d1e5ad7ab3bc6ae9b3a538a3601bccf929b0e998..0c81056c1dd7edac30e1d86bdd2103d1e2d6832f 100644 (file)
@@ -255,7 +255,7 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
 }
 #endif
 
-void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
+static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
        unsigned long offset, size_t size, unsigned int mtype, void *caller)
 {
        const struct mem_type *type;
@@ -363,7 +363,7 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
                  unsigned int mtype)
 {
        return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
-                       __builtin_return_address(0));
+                                       __builtin_return_address(0));
 }
 EXPORT_SYMBOL(__arm_ioremap_pfn);
 
@@ -371,13 +371,26 @@ void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
                                      unsigned int, void *) =
        __arm_ioremap_caller;
 
-void __iomem *
-__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
+void __iomem *ioremap(resource_size_t res_cookie, size_t size)
+{
+       return arch_ioremap_caller(res_cookie, size, MT_DEVICE,
+                                  __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap);
+
+void __iomem *ioremap_cache(resource_size_t res_cookie, size_t size)
+{
+       return arch_ioremap_caller(res_cookie, size, MT_DEVICE_CACHED,
+                                  __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_cache);
+
+void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size)
 {
-       return arch_ioremap_caller(phys_addr, size, mtype,
-               __builtin_return_address(0));
+       return arch_ioremap_caller(res_cookie, size, MT_DEVICE_WC,
+                                  __builtin_return_address(0));
 }
-EXPORT_SYMBOL(__arm_ioremap);
+EXPORT_SYMBOL(ioremap_wc);
 
 /*
  * Remap an arbitrary physical address space into the kernel virtual
@@ -431,11 +444,11 @@ void __iounmap(volatile void __iomem *io_addr)
 
 void (*arch_iounmap)(volatile void __iomem *) = __iounmap;
 
-void __arm_iounmap(volatile void __iomem *io_addr)
+void iounmap(volatile void __iomem *cookie)
 {
-       arch_iounmap(io_addr);
+       arch_iounmap(cookie);
 }
-EXPORT_SYMBOL(__arm_iounmap);
+EXPORT_SYMBOL(iounmap);
 
 #ifdef CONFIG_PCI
 static int pci_ioremap_mem_type = MT_DEVICE;
index 6ca7d9aa896f4e14804e1096407b16e9b1020456..870838a46d524141a9cb1d65980c1ba7456465cb 100644 (file)
@@ -1072,6 +1072,7 @@ void __init sanity_check_meminfo(void)
        int highmem = 0;
        phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
        struct memblock_region *reg;
+       bool should_use_highmem = false;
 
        for_each_memblock(memory, reg) {
                phys_addr_t block_start = reg->base;
@@ -1090,6 +1091,7 @@ void __init sanity_check_meminfo(void)
                                pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
                                          &block_start, &block_end);
                                memblock_remove(reg->base, reg->size);
+                               should_use_highmem = true;
                                continue;
                        }
 
@@ -1100,6 +1102,7 @@ void __init sanity_check_meminfo(void)
                                          &block_start, &block_end, &vmalloc_limit);
                                memblock_remove(vmalloc_limit, overlap_size);
                                block_end = vmalloc_limit;
+                               should_use_highmem = true;
                        }
                }
 
@@ -1134,6 +1137,9 @@ void __init sanity_check_meminfo(void)
                }
        }
 
+       if (should_use_highmem)
+               pr_notice("Consider using a HIGHMEM enabled kernel.\n");
+
        high_memory = __va(arm_lowmem_limit - 1) + 1;
 
        /*
@@ -1494,6 +1500,7 @@ void __init paging_init(const struct machine_desc *mdesc)
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
+       memblock_set_current_limit(arm_lowmem_limit);
        dma_contiguous_remap();
        devicemaps_init(mdesc);
        kmap_init();
index afd7e05d95f1884becf11913aa4b075048a4d4f8..1dd10936d68d0422b328128fbb6a234d77adee1d 100644 (file)
@@ -351,30 +351,43 @@ void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset,
 }
 EXPORT_SYMBOL(__arm_ioremap_pfn);
 
-void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
-                          size_t size, unsigned int mtype, void *caller)
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
+                                  unsigned int mtype, void *caller)
 {
-       return __arm_ioremap_pfn(pfn, offset, size, mtype);
+       return (void __iomem *)phys_addr;
 }
 
-void __iomem *__arm_ioremap(phys_addr_t phys_addr, size_t size,
-                           unsigned int mtype)
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, unsigned int, void *);
+
+void __iomem *ioremap(resource_size_t res_cookie, size_t size)
 {
-       return (void __iomem *)phys_addr;
+       return __arm_ioremap_caller(res_cookie, size, MT_DEVICE,
+                                   __builtin_return_address(0));
 }
-EXPORT_SYMBOL(__arm_ioremap);
+EXPORT_SYMBOL(ioremap);
 
-void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, unsigned int, void *);
+void __iomem *ioremap_cache(resource_size_t res_cookie, size_t size)
+{
+       return __arm_ioremap_caller(res_cookie, size, MT_DEVICE_CACHED,
+                                   __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_cache);
 
-void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
-                                  unsigned int mtype, void *caller)
+void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size)
+{
+       return __arm_ioremap_caller(res_cookie, size, MT_DEVICE_WC,
+                                   __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_wc);
+
+void __iounmap(volatile void __iomem *addr)
 {
-       return __arm_ioremap(phys_addr, size, mtype);
 }
+EXPORT_SYMBOL(__iounmap);
 
 void (*arch_iounmap)(volatile void __iomem *);
 
-void __arm_iounmap(volatile void __iomem *addr)
+void iounmap(volatile void __iomem *addr)
 {
 }
-EXPORT_SYMBOL(__arm_iounmap);
+EXPORT_SYMBOL(iounmap);
index 0716bbe198728876e81361897b69258e3489bf24..de2b246fed3808fce444b560a725ed4007464174 100644 (file)
@@ -274,7 +274,10 @@ __v7_ca15mp_setup:
 __v7_b15mp_setup:
 __v7_ca17mp_setup:
        mov     r10, #0
-1:
+1:     adr     r12, __v7_setup_stack           @ the local stack
+       stmia   r12, {r0-r5, lr}                @ v7_invalidate_l1 touches r0-r6
+       bl      v7_invalidate_l1
+       ldmia   r12, {r0-r5, lr}
 #ifdef CONFIG_SMP
        ALT_SMP(mrc     p15, 0, r0, c1, c0, 1)
        ALT_UP(mov      r0, #(1 << 6))          @ fake it for UP
@@ -283,7 +286,7 @@ __v7_ca17mp_setup:
        orreq   r0, r0, r10                     @ Enable CPU-specific SMP bits
        mcreq   p15, 0, r0, c1, c0, 1
 #endif
-       b       __v7_setup
+       b       __v7_setup_cont
 
 /*
  * Errata:
@@ -413,10 +416,11 @@ __v7_pj4b_setup:
 
 __v7_setup:
        adr     r12, __v7_setup_stack           @ the local stack
-       stmia   r12, {r0-r5, r7, r9, r11, lr}
+       stmia   r12, {r0-r5, lr}                @ v7_invalidate_l1 touches r0-r6
        bl      v7_invalidate_l1
-       ldmia   r12, {r0-r5, r7, r9, r11, lr}
+       ldmia   r12, {r0-r5, lr}
 
+__v7_setup_cont:
        and     r0, r9, #0xff000000             @ ARM?
        teq     r0, #0x41000000
        bne     __errata_finish
@@ -480,7 +484,7 @@ ENDPROC(__v7_setup)
 
        .align  2
 __v7_setup_stack:
-       .space  4 * 11                          @ 11 registers
+       .space  4 * 7                           @ 12 registers
 
        __INITDATA
 
index 4550d247e308be128b439b0735d853f4745f3618..c011e2296cb1e681863338972c6ce79f836bb6be 100644 (file)
@@ -74,32 +74,52 @@ struct jit_ctx {
 
 int bpf_jit_enable __read_mostly;
 
-static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
+static inline int call_neg_helper(struct sk_buff *skb, int offset, void *ret,
+                     unsigned int size)
+{
+       void *ptr = bpf_internal_load_pointer_neg_helper(skb, offset, size);
+
+       if (!ptr)
+               return -EFAULT;
+       memcpy(ret, ptr, size);
+       return 0;
+}
+
+static u64 jit_get_skb_b(struct sk_buff *skb, int offset)
 {
        u8 ret;
        int err;
 
-       err = skb_copy_bits(skb, offset, &ret, 1);
+       if (offset < 0)
+               err = call_neg_helper(skb, offset, &ret, 1);
+       else
+               err = skb_copy_bits(skb, offset, &ret, 1);
 
        return (u64)err << 32 | ret;
 }
 
-static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
+static u64 jit_get_skb_h(struct sk_buff *skb, int offset)
 {
        u16 ret;
        int err;
 
-       err = skb_copy_bits(skb, offset, &ret, 2);
+       if (offset < 0)
+               err = call_neg_helper(skb, offset, &ret, 2);
+       else
+               err = skb_copy_bits(skb, offset, &ret, 2);
 
        return (u64)err << 32 | ntohs(ret);
 }
 
-static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
+static u64 jit_get_skb_w(struct sk_buff *skb, int offset)
 {
        u32 ret;
        int err;
 
-       err = skb_copy_bits(skb, offset, &ret, 4);
+       if (offset < 0)
+               err = call_neg_helper(skb, offset, &ret, 4);
+       else
+               err = skb_copy_bits(skb, offset, &ret, 4);
 
        return (u64)err << 32 | ntohl(ret);
 }
@@ -536,9 +556,6 @@ static int build_body(struct jit_ctx *ctx)
                case BPF_LD | BPF_B | BPF_ABS:
                        load_order = 0;
 load:
-                       /* the interpreter will deal with the negative K */
-                       if ((int)k < 0)
-                               return -ENOTSUPP;
                        emit_mov_i(r_off, k, ctx);
 load_common:
                        ctx->seen |= SEEN_DATA | SEEN_CALL;
@@ -547,12 +564,24 @@ load_common:
                                emit(ARM_SUB_I(r_scratch, r_skb_hl,
                                               1 << load_order), ctx);
                                emit(ARM_CMP_R(r_scratch, r_off), ctx);
-                               condt = ARM_COND_HS;
+                               condt = ARM_COND_GE;
                        } else {
                                emit(ARM_CMP_R(r_skb_hl, r_off), ctx);
                                condt = ARM_COND_HI;
                        }
 
+                       /*
+                        * test for negative offset, only if we are
+                        * currently scheduled to take the fast
+                        * path. this will update the flags so that
+                        * the slowpath instruction are ignored if the
+                        * offset is negative.
+                        *
+                        * for loard_order == 0 the HI condition will
+                        * make loads at offset 0 take the slow path too.
+                        */
+                       _emit(condt, ARM_CMP_I(r_off, 0), ctx);
+
                        _emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data),
                              ctx);
 
@@ -860,9 +889,11 @@ b_epilogue:
                        off = offsetof(struct sk_buff, vlan_tci);
                        emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
                        if (code == (BPF_ANC | SKF_AD_VLAN_TAG))
-                               OP_IMM3(ARM_AND, r_A, r_A, VLAN_VID_MASK, ctx);
-                       else
-                               OP_IMM3(ARM_AND, r_A, r_A, VLAN_TAG_PRESENT, ctx);
+                               OP_IMM3(ARM_AND, r_A, r_A, ~VLAN_TAG_PRESENT, ctx);
+                       else {
+                               OP_IMM3(ARM_LSR, r_A, r_A, 12, ctx);
+                               OP_IMM3(ARM_AND, r_A, r_A, 0x1, ctx);
+                       }
                        break;
                case BPF_ANC | SKF_AD_QUEUE:
                        ctx->seen |= SEEN_SKB;
index 9d259d94e429c4cc493542ad4cf238a513b13743..1160434eece0509c3797733b49e8fcb1262e42e7 100644 (file)
@@ -14,7 +14,7 @@ VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
 VDSO_LDFLAGS += -nostdlib -shared
 VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
 VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id)
-VDSO_LDFLAGS += $(call cc-option, -fuse-ld=bfd)
+VDSO_LDFLAGS += $(call cc-ldoption, -fuse-ld=bfd)
 
 obj-$(CONFIG_VDSO) += vdso.o
 extra-$(CONFIG_VDSO) += vdso.lds
index 9005b07296c8b38c728ff6466ebd365fda1753ed..aedec81d11988181e3e6f0631113fd01e4737ac8 100644 (file)
  * it does.
  */
 
-#define _GNU_SOURCE
-
 #include <byteswap.h>
 #include <elf.h>
 #include <errno.h>
-#include <error.h>
 #include <fcntl.h>
+#include <stdarg.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #define EF_ARM_ABI_FLOAT_HARD 0x400
 #endif
 
+static int failed;
+static const char *argv0;
 static const char *outfile;
 
+static void fail(const char *fmt, ...)
+{
+       va_list ap;
+
+       failed = 1;
+       fprintf(stderr, "%s: ", argv0);
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       exit(EXIT_FAILURE);
+}
+
 static void cleanup(void)
 {
-       if (error_message_count > 0 && outfile != NULL)
+       if (failed && outfile != NULL)
                unlink(outfile);
 }
 
@@ -119,68 +131,66 @@ int main(int argc, char **argv)
        int infd;
 
        atexit(cleanup);
+       argv0 = argv[0];
 
        if (argc != 3)
-               error(EXIT_FAILURE, 0, "Usage: %s [infile] [outfile]", argv[0]);
+               fail("Usage: %s [infile] [outfile]\n", argv[0]);
 
        infile = argv[1];
        outfile = argv[2];
 
        infd = open(infile, O_RDONLY);
        if (infd < 0)
-               error(EXIT_FAILURE, errno, "Cannot open %s", infile);
+               fail("Cannot open %s: %s\n", infile, strerror(errno));
 
        if (fstat(infd, &stat) != 0)
-               error(EXIT_FAILURE, errno, "Failed stat for %s", infile);
+               fail("Failed stat for %s: %s\n", infile, strerror(errno));
 
        inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0);
        if (inbuf == MAP_FAILED)
-               error(EXIT_FAILURE, errno, "Failed to map %s", infile);
+               fail("Failed to map %s: %s\n", infile, strerror(errno));
 
        close(infd);
 
        inhdr = inbuf;
 
        if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0)
-               error(EXIT_FAILURE, 0, "Not an ELF file");
+               fail("Not an ELF file\n");
 
        if (inhdr->e_ident[EI_CLASS] != ELFCLASS32)
-               error(EXIT_FAILURE, 0, "Unsupported ELF class");
+               fail("Unsupported ELF class\n");
 
        swap = inhdr->e_ident[EI_DATA] != HOST_ORDER;
 
        if (read_elf_half(inhdr->e_type, swap) != ET_DYN)
-               error(EXIT_FAILURE, 0, "Not a shared object");
+               fail("Not a shared object\n");
 
-       if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) {
-               error(EXIT_FAILURE, 0, "Unsupported architecture %#x",
-                     inhdr->e_machine);
-       }
+       if (read_elf_half(inhdr->e_machine, swap) != EM_ARM)
+               fail("Unsupported architecture %#x\n", inhdr->e_machine);
 
        e_flags = read_elf_word(inhdr->e_flags, swap);
 
        if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) {
-               error(EXIT_FAILURE, 0, "Unsupported EABI version %#x",
-                     EF_ARM_EABI_VERSION(e_flags));
+               fail("Unsupported EABI version %#x\n",
+                    EF_ARM_EABI_VERSION(e_flags));
        }
 
        if (e_flags & EF_ARM_ABI_FLOAT_HARD)
-               error(EXIT_FAILURE, 0,
-                     "Unexpected hard-float flag set in e_flags");
+               fail("Unexpected hard-float flag set in e_flags\n");
 
        clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT);
 
        outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
        if (outfd < 0)
-               error(EXIT_FAILURE, errno, "Cannot open %s", outfile);
+               fail("Cannot open %s: %s\n", outfile, strerror(errno));
 
        if (ftruncate(outfd, stat.st_size) != 0)
-               error(EXIT_FAILURE, errno, "Cannot truncate %s", outfile);
+               fail("Cannot truncate %s: %s\n", outfile, strerror(errno));
 
        outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
                      outfd, 0);
        if (outbuf == MAP_FAILED)
-               error(EXIT_FAILURE, errno, "Failed to map %s", outfile);
+               fail("Failed to map %s: %s\n", outfile, strerror(errno));
 
        close(outfd);
 
@@ -195,7 +205,7 @@ int main(int argc, char **argv)
        }
 
        if (msync(outbuf, stat.st_size, MS_SYNC) != 0)
-               error(EXIT_FAILURE, errno, "Failed to sync %s", outfile);
+               fail("Failed to sync %s: %s\n", outfile, strerror(errno));
 
        return EXIT_SUCCESS;
 }
index 0f6edb14b7e436bc60fee0908e3ff7a45cd3ff41..318175f62c24d0ec4df68a555d02f2bd2a920cfc 100644 (file)
@@ -23,9 +23,9 @@ config ARM64
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
        select COMMON_CLK
-       select EDAC_SUPPORT
        select CPU_PM if (SUSPEND || CPU_IDLE)
        select DCACHE_WORD_ACCESS
+       select EDAC_SUPPORT
        select GENERIC_ALLOCATOR
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
index 83578e766b945ae2c35b41b93813a8c29ec15c1b..4c55833d8a41a0b361faaf66ad72dffcc6885f02 100644 (file)
                device_type = "memory";
                reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
        };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+               button@1 {
+                       label = "POWER";
+                       linux,code = <116>;
+                       linux,input-type = <0x1>;
+                       interrupts = <0x0 0x2d 0x1>;
+               };
+       };
 };
 
 &pcie0clk {
index 0689c3fb56e3d84fe3ed7790f4a6b25835c86555..58093edeea2e5b7513321ff5ddfcb305ac873638 100644 (file)
                        device_type = "dma";
                        reg = <0x0 0x1f270000 0x0 0x10000>,
                              <0x0 0x1f200000 0x0 0x10000>,
-                             <0x0 0x1b008000 0x0 0x2000>,
+                             <0x0 0x1b000000 0x0 0x400000>,
                              <0x0 0x1054a000 0x0 0x100>;
                        interrupts = <0x0 0x82 0x4>,
                                     <0x0 0xb8 0x4>,
index c5c98b91514e90186e6bbe432a1c0a7d880ed9e9..bb3c072096760836ad004b1e9bd485ecfaeb9b24 100644 (file)
@@ -1,6 +1,7 @@
 dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb
 dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb juno-r1.dtb
 dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb
+dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2f-1xv7-ca53x2.dtb
 
 always         := $(dtb-y)
 subdir-y       := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts b/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts
new file mode 100644 (file)
index 0000000..5b1d018
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * LogicTile Express 20MG
+ * V2F-1XV7
+ *
+ * Cortex-A53 (2 cores) Soft Macrocell Model
+ *
+ * HBI-0247C
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+       model = "V2F-1XV7 Cortex-A53x2 SMM";
+       arm,hbi = <0x247>;
+       arm,vexpress,site = <0xf>;
+       compatible = "arm,vexpress,v2f-1xv7,ca53x2", "arm,vexpress,v2f-1xv7", "arm,vexpress";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       chosen {
+               stdout-path = "serial0:38400n8";
+       };
+
+       aliases {
+               serial0 = &v2m_serial0;
+               serial1 = &v2m_serial1;
+               serial2 = &v2m_serial2;
+               serial3 = &v2m_serial3;
+               i2c0 = &v2m_i2c_dvi;
+               i2c1 = &v2m_i2c_pcie;
+       };
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53", "arm,armv8";
+                       reg = <0 0>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a53", "arm,armv8";
+                       reg = <0 1>;
+                       next-level-cache = <&L2_0>;
+               };
+
+               L2_0: l2-cache0 {
+                       compatible = "cache";
+               };
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0 0x80000000 0 0x80000000>; /* 2GB @ 2GB */
+       };
+
+       gic: interrupt-controller@2c001000 {
+               compatible = "arm,gic-400";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0 0x2c001000 0 0x1000>,
+                     <0 0x2c002000 0 0x2000>,
+                     <0 0x2c004000 0 0x2000>,
+                     <0 0x2c006000 0 0x2000>;
+               interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
+       pmu {
+               compatible = "arm,armv8-pmuv3";
+               interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+       };
+
+       dcc {
+               compatible = "arm,vexpress,config-bus";
+               arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+               smbclk: osc@4 {
+                       /* SMC clock */
+                       compatible = "arm,vexpress-osc";
+                       arm,vexpress-sysreg,func = <1 4>;
+                       freq-range = <40000000 40000000>;
+                       #clock-cells = <0>;
+                       clock-output-names = "smclk";
+               };
+
+               volt@0 {
+                       /* VIO to expansion board above */
+                       compatible = "arm,vexpress-volt";
+                       arm,vexpress-sysreg,func = <2 0>;
+                       regulator-name = "VIO_UP";
+                       regulator-min-microvolt = <800000>;
+                       regulator-max-microvolt = <1800000>;
+                       regulator-always-on;
+               };
+
+               volt@1 {
+                       /* 12V from power connector J6 */
+                       compatible = "arm,vexpress-volt";
+                       arm,vexpress-sysreg,func = <2 1>;
+                       regulator-name = "12";
+                       regulator-always-on;
+               };
+
+               temp@0 {
+                       /* FPGA temperature */
+                       compatible = "arm,vexpress-temp";
+                       arm,vexpress-sysreg,func = <4 0>;
+                       label = "FPGA";
+               };
+       };
+
+       smb {
+               compatible = "simple-bus";
+
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0 0 0 0x08000000 0x04000000>,
+                        <1 0 0 0x14000000 0x04000000>,
+                        <2 0 0 0x18000000 0x04000000>,
+                        <3 0 0 0x1c000000 0x04000000>,
+                        <4 0 0 0x0c000000 0x04000000>,
+                        <5 0 0 0x10000000 0x04000000>;
+
+               #interrupt-cells = <1>;
+               interrupt-map-mask = <0 0 63>;
+               interrupt-map = <0 0  0 &gic GIC_SPI  0 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  1 &gic GIC_SPI  1 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  2 &gic GIC_SPI  2 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  3 &gic GIC_SPI  3 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  4 &gic GIC_SPI  4 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  5 &gic GIC_SPI  5 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  6 &gic GIC_SPI  6 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  7 &gic GIC_SPI  7 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  8 &gic GIC_SPI  8 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0  9 &gic GIC_SPI  9 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 10 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 11 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 12 &gic GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 13 &gic GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 14 &gic GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 15 &gic GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 16 &gic GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 17 &gic GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 18 &gic GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 19 &gic GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 20 &gic GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 21 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 22 &gic GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 23 &gic GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 24 &gic GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 25 &gic GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 26 &gic GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 27 &gic GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 28 &gic GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 29 &gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 30 &gic GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 31 &gic GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 32 &gic GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 33 &gic GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 34 &gic GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 35 &gic GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 36 &gic GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 37 &gic GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 38 &gic GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 39 &gic GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 40 &gic GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 41 &gic GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+                               <0 0 42 &gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+
+               /include/ "../../../../arm/boot/dts/vexpress-v2m-rs1.dtsi"
+       };
+};
index d8c0bdc51882a18cc311431e8e17776f5847ca30..9cb7cf94284a66b07619f4b2a4ab042c803c5f03 100644 (file)
                gic0: interrupt-controller@8010,00000000 {
                        compatible = "arm,gic-v3";
                        #interrupt-cells = <3>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
                        interrupt-controller;
                        reg = <0x8010 0x00000000 0x0 0x010000>, /* GICD */
                              <0x8010 0x80000000 0x0 0x600000>; /* GICR */
                        interrupts = <1 9 0xf04>;
+
+                       its: gic-its@8010,00020000 {
+                               compatible = "arm,gic-v3-its";
+                               msi-controller;
+                               reg = <0x8010 0x20000 0x0 0x200000>;
+                       };
                };
 
                uaa0: serial@87e0,24000000 {
index f38c94f1d89834ebec7c4ab4d514e27b368e6bd5..4e17e7ede33d5a3ebacd8c3a13d31916b009a36b 100644 (file)
@@ -83,6 +83,7 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_AHCI_CEVA=y
 CONFIG_AHCI_XGENE=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_PATA_OF_PLATFORM=y
index b112a39834d046b65ea8af2df2555051da1223c3..70fd9ffb58cfc08e82f3a978e6630c70eaeb1840 100644 (file)
@@ -25,6 +25,7 @@ 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
index 39248d3adf5d8b2858a9e01aa92209e70f78772b..406485ed110af9fb12ce8040815355442d088444 100644 (file)
 #include <asm/psci.h>
 #include <asm/smp_plat.h>
 
+/* Macros for consistency checks of the GICC subtable of MADT */
+#define ACPI_MADT_GICC_LENGTH  \
+       (acpi_gbl_FADT.header.revision < 6 ? 76 : 80)
+
+#define BAD_MADT_GICC_ENTRY(entry, end)                                                \
+       (!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||       \
+        (entry)->header.length != ACPI_MADT_GICC_LENGTH)
+
 /* Basic configuration for ACPI */
 #ifdef CONFIG_ACPI
 /* ACPI table mapping after acpi_gbl_permanent_mmap is set */
diff --git a/arch/arm64/include/asm/mm-arch-hooks.h b/arch/arm64/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 562b655..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_ARM64_MM_ARCH_HOOKS_H
-#define _ASM_ARM64_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_ARM64_MM_ARCH_HOOKS_H */
index 9d4aa18f2a825256537a7d7e33c606d89d003ee7..e8ca6eaedd0252e2056530d71d519f423931d323 100644 (file)
@@ -122,12 +122,12 @@ static int __init uefi_init(void)
 
        /* Show what we know for posterity */
        c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
-                            sizeof(vendor));
+                            sizeof(vendor) * sizeof(efi_char16_t));
        if (c16) {
                for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
                        vendor[i] = c16[i];
                vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor));
+               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
        }
 
        pr_info("EFI v%u.%.02u by %s\n",
index a7691a37866834375283b56501e6b11f23f49de8..e16351819fed9ada8575f117c4777232da0d72b9 100644 (file)
@@ -352,8 +352,8 @@ el1_inv:
        // TODO: add support for undefined instructions in kernel mode
        enable_dbg
        mov     x0, sp
+       mov     x2, x1
        mov     x1, #BAD_SYNC
-       mrs     x2, esr_el1
        b       bad_mode
 ENDPROC(el1_sync)
 
@@ -553,7 +553,7 @@ el0_inv:
        ct_user_exit
        mov     x0, sp
        mov     x1, #BAD_SYNC
-       mrs     x2, esr_el1
+       mov     x2, x25
        bl      bad_mode
        b       ret_to_user
 ENDPROC(el0_sync)
@@ -585,7 +585,8 @@ ENDPROC(el0_irq)
  *
  */
 ENTRY(cpu_switch_to)
-       add     x8, x0, #THREAD_CPU_CONTEXT
+       mov     x10, #THREAD_CPU_CONTEXT
+       add     x8, x0, x10
        mov     x9, sp
        stp     x19, x20, [x8], #16             // store callee-saved registers
        stp     x21, x22, [x8], #16
@@ -594,7 +595,7 @@ ENTRY(cpu_switch_to)
        stp     x27, x28, [x8], #16
        stp     x29, x9, [x8], #16
        str     lr, [x8]
-       add     x8, x1, #THREAD_CPU_CONTEXT
+       add     x8, x1, x10
        ldp     x19, x20, [x8], #16             // restore callee-saved registers
        ldp     x21, x22, [x8], #16
        ldp     x23, x24, [x8], #16
index bd9bfaa9269bc59980e89209e22ac0286288f9ef..f332d5d1f6b40c1b5382301d103fe3ed588ea4c1 100644 (file)
 
 ENTRY(compat_sys_sigreturn_wrapper)
        mov     x0, sp
-       mov     x27, #0         // prevent syscall restart handling (why)
        b       compat_sys_sigreturn
 ENDPROC(compat_sys_sigreturn_wrapper)
 
 ENTRY(compat_sys_rt_sigreturn_wrapper)
        mov     x0, sp
-       mov     x27, #0         // prevent syscall restart handling (why)
        b       compat_sys_rt_sigreturn
 ENDPROC(compat_sys_rt_sigreturn_wrapper)
 
index 240b75c0e94fdc435a672b740b08d4a848915295..463fa2e7e34c10ba56f2cd4a10e208062feff3d9 100644 (file)
@@ -61,7 +61,7 @@ void __init init_IRQ(void)
 static bool migrate_one_irq(struct irq_desc *desc)
 {
        struct irq_data *d = irq_desc_get_irq_data(desc);
-       const struct cpumask *affinity = d->affinity;
+       const struct cpumask *affinity = irq_data_get_affinity_mask(d);
        struct irq_chip *c;
        bool ret = false;
 
@@ -81,7 +81,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
        if (!c->irq_set_affinity)
                pr_debug("IRQ%u: unable to set affinity\n", d->irq);
        else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret)
-               cpumask_copy(d->affinity, affinity);
+               cpumask_copy(irq_data_get_affinity_mask(d), affinity);
 
        return ret;
 }
index 1670f15ef69e34972986081deb9b1f87b0bb2bb3..948f0ad2de231b5e3f5efa62e204162cadf26503 100644 (file)
@@ -168,7 +168,8 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitely for the right codes here.
                 */
-               if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+               if (from->si_signo == SIGBUS &&
+                   (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 #endif
                break;
@@ -201,8 +202,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE))
index 695801a54ca54dac465c2b421a822658e571cc88..50fb4696654ea56b2efc28741c6c45d38d796235 100644 (file)
@@ -438,7 +438,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
        struct acpi_madt_generic_interrupt *processor;
 
        processor = (struct acpi_madt_generic_interrupt *)header;
-       if (BAD_MADT_ENTRY(processor, end))
+       if (BAD_MADT_GICC_ENTRY(processor, end))
                return -EINVAL;
 
        acpi_table_print_madt_entry(header);
index ec37ab3f524f303419d2cc3a82b79c119e61de1d..97bc68f4c689f28eac7188f5e0b792b5293c37da 100644 (file)
@@ -199,16 +199,15 @@ up_fail:
  */
 void update_vsyscall(struct timekeeper *tk)
 {
-       struct timespec xtime_coarse;
        u32 use_syscall = strcmp(tk->tkr_mono.clock->name, "arch_sys_counter");
 
        ++vdso_data->tb_seq_count;
        smp_wmb();
 
-       xtime_coarse = __current_kernel_time();
        vdso_data->use_syscall                  = use_syscall;
-       vdso_data->xtime_coarse_sec             = xtime_coarse.tv_sec;
-       vdso_data->xtime_coarse_nsec            = xtime_coarse.tv_nsec;
+       vdso_data->xtime_coarse_sec             = tk->xtime_sec;
+       vdso_data->xtime_coarse_nsec            = tk->tkr_mono.xtime_nsec >>
+                                                       tk->tkr_mono.shift;
        vdso_data->wtm_clock_sec                = tk->wall_to_monotonic.tv_sec;
        vdso_data->wtm_clock_nsec               = tk->wall_to_monotonic.tv_nsec;
 
index 9d84feb41a16601e411976aff3a2bc87a0d7dcbe..773d37a14039d9bb456f0896e022c4a3e1415773 100644 (file)
@@ -4,5 +4,3 @@ obj-y                           := dma-mapping.o extable.o fault.o init.o \
                                   context.o proc.o pageattr.o
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_ARM64_PTDUMP)     += dump.o
-
-CFLAGS_mmu.o                   := -I$(srctree)/scripts/dtc/libfdt/
index 1d66afdfac079bcf78a8dc230ed326a9d2fbfa12..f61f2dd67464746c728474a7b5503dd7dfbdcb67 100644 (file)
@@ -12,6 +12,7 @@ generic-y += irq_work.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 += preempt.h
diff --git a/arch/avr32/include/asm/mm-arch-hooks.h b/arch/avr32/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 145452f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_AVR32_MM_ARCH_HOOKS_H
-#define _ASM_AVR32_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_AVR32_MM_ARCH_HOOKS_H */
index d0f771be9e96eda02c1045bbb5702cc9b9f74b8d..a124c55733dbf7dc19e61aacbf74671ff149de83 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <mach/pm.h>
 
+static bool disable_cpu_idle_poll;
 
 static cycle_t read_cycle_count(struct clocksource *cs)
 {
@@ -80,45 +81,45 @@ static int comparator_next_event(unsigned long delta,
        return 0;
 }
 
-static void comparator_mode(enum clock_event_mode mode,
-               struct clock_event_device *evdev)
+static int comparator_shutdown(struct clock_event_device *evdev)
 {
-       switch (mode) {
-       case CLOCK_EVT_MODE_ONESHOT:
-               pr_debug("%s: start\n", evdev->name);
-               /* FALLTHROUGH */
-       case CLOCK_EVT_MODE_RESUME:
+       pr_debug("%s: %s\n", __func__, evdev->name);
+       sysreg_write(COMPARE, 0);
+
+       if (disable_cpu_idle_poll) {
+               disable_cpu_idle_poll = false;
                /*
-                * If we're using the COUNT and COMPARE registers we
-                * need to force idle poll.
+                * Only disable idle poll if we have forced that
+                * in a previous call.
                 */
-               cpu_idle_poll_ctrl(true);
-               break;
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-               sysreg_write(COMPARE, 0);
-               pr_debug("%s: stop\n", evdev->name);
-               if (evdev->mode == CLOCK_EVT_MODE_ONESHOT ||
-                   evdev->mode == CLOCK_EVT_MODE_RESUME) {
-                       /*
-                        * Only disable idle poll if we have forced that
-                        * in a previous call.
-                        */
-                       cpu_idle_poll_ctrl(false);
-               }
-               break;
-       default:
-               BUG();
+               cpu_idle_poll_ctrl(false);
        }
+       return 0;
+}
+
+static int comparator_set_oneshot(struct clock_event_device *evdev)
+{
+       pr_debug("%s: %s\n", __func__, evdev->name);
+
+       disable_cpu_idle_poll = true;
+       /*
+        * If we're using the COUNT and COMPARE registers we
+        * need to force idle poll.
+        */
+       cpu_idle_poll_ctrl(true);
+
+       return 0;
 }
 
 static struct clock_event_device comparator = {
-       .name           = "avr32_comparator",
-       .features       = CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 16,
-       .rating         = 50,
-       .set_next_event = comparator_next_event,
-       .set_mode       = comparator_mode,
+       .name                   = "avr32_comparator",
+       .features               = CLOCK_EVT_FEAT_ONESHOT,
+       .shift                  = 16,
+       .rating                 = 50,
+       .set_next_event         = comparator_next_event,
+       .set_state_shutdown     = comparator_shutdown,
+       .set_state_oneshot      = comparator_set_oneshot,
+       .tick_resume            = comparator_set_oneshot,
 };
 
 void read_persistent_clock(struct timespec *ts)
index 23b1a97fae7ad686acc581c5888e95d5e4928a1e..52c179bec0cc6c69d4430324a0a581f66e066a6d 100644 (file)
@@ -80,6 +80,9 @@ int clk_enable(struct clk *clk)
 {
        unsigned long flags;
 
+       if (!clk)
+               return 0;
+
        spin_lock_irqsave(&clk_lock, flags);
        __clk_enable(clk);
        spin_unlock_irqrestore(&clk_lock, flags);
@@ -106,6 +109,9 @@ void clk_disable(struct clk *clk)
 {
        unsigned long flags;
 
+       if (IS_ERR_OR_NULL(clk))
+               return;
+
        spin_lock_irqsave(&clk_lock, flags);
        __clk_disable(clk);
        spin_unlock_irqrestore(&clk_lock, flags);
@@ -117,6 +123,9 @@ unsigned long clk_get_rate(struct clk *clk)
        unsigned long flags;
        unsigned long rate;
 
+       if (!clk)
+               return 0;
+
        spin_lock_irqsave(&clk_lock, flags);
        rate = clk->get_rate(clk);
        spin_unlock_irqrestore(&clk_lock, flags);
@@ -129,6 +138,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 {
        unsigned long flags, actual_rate;
 
+       if (!clk)
+               return 0;
+
        if (!clk->set_rate)
                return -ENOSYS;
 
@@ -145,6 +157,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        unsigned long flags;
        long ret;
 
+       if (!clk)
+               return 0;
+
        if (!clk->set_rate)
                return -ENOSYS;
 
@@ -161,6 +176,9 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        unsigned long flags;
        int ret;
 
+       if (!clk)
+               return 0;
+
        if (!clk->set_parent)
                return -ENOSYS;
 
@@ -174,7 +192,7 @@ EXPORT_SYMBOL(clk_set_parent);
 
 struct clk *clk_get_parent(struct clk *clk)
 {
-       return clk->parent;
+       return !clk ? NULL : clk->parent;
 }
 EXPORT_SYMBOL(clk_get_parent);
 
index 07051a63415d712bcd17469d6db5460c1353030e..61cd1e786a142c440caa231a665349ed3d8f8e01 100644 (file)
@@ -21,6 +21,7 @@ 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 += mutex.h
diff --git a/arch/blackfin/include/asm/mm-arch-hooks.h b/arch/blackfin/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 1c5211e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_BLACKFIN_MM_ARCH_HOOKS_H
-#define _ASM_BLACKFIN_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_BLACKFIN_MM_ARCH_HOOKS_H */
index 7aeb322729754f25a991a6358e1e5b4a9ad39118..f17c4dc6050c7d23ade635f749aa75eed8f0ac1d 100644 (file)
@@ -26,6 +26,7 @@ generic-y += kdebug.h
 generic-y += kmap_types.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
diff --git a/arch/c6x/include/asm/mm-arch-hooks.h b/arch/c6x/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index bb3c4a6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_C6X_MM_ARCH_HOOKS_H
-#define _ASM_C6X_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_C6X_MM_ARCH_HOOKS_H */
index 4dda9bd6b8fbd17219efc7d103207719282e5a33..e989cee7741489b0eaec0069d0c5fe87bcce1e4a 100644 (file)
@@ -1464,7 +1464,7 @@ static inline void handle_rx_packet(struct sync_port *port)
                if (port->write_ts_idx == NBR_IN_DESCR)
                        port->write_ts_idx = 0;
                idx = port->write_ts_idx++;
-               do_posix_clock_monotonic_gettime(&port->timestamp[idx]);
+               ktime_get_ts(&port->timestamp[idx]);
                port->in_buffer_len += port->inbufchunk;
        }
        spin_unlock_irqrestore(&port->lock, flags);
index d294f6aaff1d1631dc085e1e174bc8515e59b5cb..ad2244f35bca0c991e8c42702edb613dc8aa5334 100644 (file)
@@ -18,6 +18,7 @@ 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 += module.h
 generic-y += percpu.h
 generic-y += preempt.h
diff --git a/arch/cris/include/asm/mm-arch-hooks.h b/arch/cris/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 314f774..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_CRIS_MM_ARCH_HOOKS_H
-#define _ASM_CRIS_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_CRIS_MM_ARCH_HOOKS_H */
index 30edce31e5c21e1e7cba707833f10a49d12eb42c..8e47b832cc7684af7a10d2a0680651cf5bf8cc0d 100644 (file)
@@ -4,5 +4,6 @@ generic-y += cputime.h
 generic-y += exec.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += preempt.h
 generic-y += trace_clock.h
diff --git a/arch/frv/include/asm/mm-arch-hooks.h b/arch/frv/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 51d13a8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_FRV_MM_ARCH_HOOKS_H
-#define _ASM_FRV_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_FRV_MM_ARCH_HOOKS_H */
index 00379d64f707860c0101d6edb6be5f3aa3b9c35f..70e6ae1e700673e3acbd03452d22f57db9c1166d 100644 (file)
@@ -33,6 +33,7 @@ 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
index 5ade4a163558f924d85dfa5ec058bd4ba8ab1379..daee37bd09991a3edf732451587e59a8db001d54 100644 (file)
@@ -28,6 +28,7 @@ generic-y += kmap_types.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
diff --git a/arch/hexagon/include/asm/mm-arch-hooks.h b/arch/hexagon/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 05e8b93..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_HEXAGON_MM_ARCH_HOOKS_H
-#define _ASM_HEXAGON_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_HEXAGON_MM_ARCH_HOOKS_H */
index ccff13d33fa21e89e31570a35b33f36c2ec11ad7..9de3ba12f6b97c0f8722e2f929c70fbae429fd34 100644 (file)
@@ -4,6 +4,7 @@ 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
 generic-y += trace_clock.h
 generic-y += vtime.h
diff --git a/arch/ia64/include/asm/mm-arch-hooks.h b/arch/ia64/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index ab4b5c6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_IA64_MM_ARCH_HOOKS_H
-#define _ASM_IA64_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_IA64_MM_ARCH_HOOKS_H */
index ba1cdc0187315113e5a79850ea8b6dc08038800c..e0eb704ca1fa93755d678e82c2336c8e188a34f0 100644 (file)
@@ -4,6 +4,7 @@ generic-y += cputime.h
 generic-y += exec.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += module.h
 generic-y += preempt.h
 generic-y += sections.h
index 0c3f25ee3381d9fad606ea36bb09682d362a87d8..f8de767ce2bcc763979ef6e08d4ef4f862a89efb 100644 (file)
@@ -174,6 +174,11 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define iowrite16 writew
 #define iowrite32 writel
 
+#define ioread16be(addr)       be16_to_cpu(readw(addr))
+#define ioread32be(addr)       be32_to_cpu(readl(addr))
+#define iowrite16be(v, addr)   writew(cpu_to_be16(v), (addr))
+#define iowrite32be(v, addr)   writel(cpu_to_be32(v), (addr))
+
 #define mmiowb()
 
 #define flush_write_buffers() do { } while (0)  /* M32R_FIXME */
diff --git a/arch/m32r/include/asm/mm-arch-hooks.h b/arch/m32r/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 6d60b47..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_M32R_MM_ARCH_HOOKS_H
-#define _ASM_M32R_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_M32R_MM_ARCH_HOOKS_H */
index 33013dfcd3e1d58fb0b0f3495ce1956c76233340..c496d48a8c8d07f9c27cb2bf799a3f078b5c1674 100644 (file)
@@ -125,6 +125,13 @@ endif # M68KCLASSIC
 
 if COLDFIRE
 
+choice
+       prompt "ColdFire SoC type"
+       default M520x
+       help
+         Select the type of ColdFire System-on-Chip (SoC) that you want
+         to build for.
+
 config M5206
        bool "MCF5206"
        depends on !MMU
@@ -174,9 +181,6 @@ config M525x
        help
          Freescale (Motorola) Coldfire 5251/5253 processor support.
 
-config M527x
-       bool
-
 config M5271
        bool "MCF5271"
        depends on !MMU
@@ -223,9 +227,6 @@ config M5307
        help
          Motorola ColdFire 5307 processor support.
 
-config M53xx
-       bool
-
 config M532x
        bool "MCF532x"
        depends on !MMU
@@ -251,9 +252,6 @@ config M5407
        help
          Motorola ColdFire 5407 processor support.
 
-config M54xx
-       bool
-
 config M547x
        bool "MCF547x"
        select M54xx
@@ -280,6 +278,17 @@ config M5441x
        help
          Freescale Coldfire 54410/54415/54416/54417/54418 processor support.
 
+endchoice
+
+config M527x
+       bool
+
+config M53xx
+       bool
+
+config M54xx
+       bool
+
 endif # COLDFIRE
 
 
@@ -416,22 +425,18 @@ config HAVE_MBAR
 config HAVE_IPSBAR
        bool
 
-config CLOCK_SET
-       bool "Enable setting the CPU clock frequency"
-       depends on COLDFIRE
-       default n
-       help
-         On some CPU's you do not need to know what the core CPU clock
-         frequency is. On these you can disable clock setting. On some
-         traditional 68K parts, and on all ColdFire parts you need to set
-         the appropriate CPU clock frequency. On these devices many of the
-         onboard peripherals derive their timing from the master CPU clock
-         frequency.
-
 config CLOCK_FREQ
        int "Set the core clock frequency"
+       default "25000000" if M5206
+       default "54000000" if M5206e
+       default "166666666" if M520x
+       default "140000000" if M5249
+       default "150000000" if M527x || M523x
+       default "90000000" if M5307
+       default "50000000" if M5407
+       default "266000000" if M54xx
        default "66666666"
-       depends on CLOCK_SET
+       depends on COLDFIRE
        help
          Define the CPU clock frequency in use. This is the core clock
          frequency, it may or may not be the same as the external clock
index e7292f460af45665ac7cdbef46c02a56f4b07921..4c7b7938d53af01eb5a154b9f916c35c8ba72974 100644 (file)
@@ -1,10 +1,6 @@
-# CONFIG_MMU is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -16,17 +12,12 @@ CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
-CONFIG_M520x=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=166666666
-CONFIG_CLOCK_DIV=2
-CONFIG_M5208EVB=y
+# CONFIG_MMU is not set
 # CONFIG_4KSTACKS is not set
 CONFIG_RAMBASE=0x40000000
 CONFIG_RAMSIZE=0x2000000
 CONFIG_VECTORBASE=0x40000000
 CONFIG_KERNELBASE=0x40020000
-CONFIG_RAM16BIT=y
 CONFIG_BINFMT_FLAT=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -40,24 +31,19 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_FEC=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
+# CONFIG_UNIX98_PTYS is not set
 CONFIG_SERIAL_MCF=y
 CONFIG_SERIAL_MCF_BAUDRATE=115200
 CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
@@ -68,8 +54,6 @@ CONFIG_EXT2_FS=y
 CONFIG_ROMFS_FS=y
 CONFIG_ROMFS_BACKED_BY_MTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_FULLDEBUG=y
 CONFIG_BOOTPARAM=y
 CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
+CONFIG_FULLDEBUG=y
index 0cd4b39f325b6c609a385f31de4cf4c76db2a957..a782f368650fe9597625560bfc39663094350f80 100644 (file)
@@ -1,10 +1,6 @@
-# CONFIG_MMU is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -16,10 +12,8 @@ CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
 CONFIG_M5249=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=140000000
-CONFIG_CLOCK_DIV=2
 CONFIG_M5249C3=y
 CONFIG_RAMBASE=0x00000000
 CONFIG_RAMSIZE=0x00800000
@@ -38,23 +32,18 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_PPP=y
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
 CONFIG_SERIAL_MCF=y
 CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_EXT2_FS=y
@@ -62,7 +51,5 @@ CONFIG_EXT2_FS=y
 CONFIG_ROMFS_FS=y
 CONFIG_ROMFS_BACKED_BY_MTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_BOOTPARAM=y
 CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
index a60cb35091352d20399c39fbfe1cd863b072a5b8..6f5fb92f5cbf2e64c907d18b1eab7322c67f5dbd 100644 (file)
@@ -1,10 +1,6 @@
-# CONFIG_MMU is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -16,8 +12,8 @@ CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
 CONFIG_M5272=y
-CONFIG_CLOCK_SET=y
 CONFIG_M5272C3=y
 CONFIG_RAMBASE=0x00000000
 CONFIG_RAMSIZE=0x00800000
@@ -36,23 +32,18 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_FEC=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
+# CONFIG_UNIX98_PTYS is not set
 CONFIG_SERIAL_MCF=y
 CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_EXT2_FS=y
@@ -61,6 +52,5 @@ CONFIG_EXT2_FS=y
 CONFIG_ROMFS_FS=y
 CONFIG_ROMFS_BACKED_BY_MTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_BOOTPARAM=y
 CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
index e6502ab7cb2fee0ac7b2bd7a1089e41450f05780..b5d7cd1ce8562359f1ef52290f04728b053b2935 100644 (file)
@@ -1,10 +1,6 @@
-# CONFIG_MMU is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -16,11 +12,8 @@ CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
 CONFIG_M5275=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=150000000
-CONFIG_CLOCK_DIV=2
-CONFIG_M5275EVB=y
 # CONFIG_4KSTACKS is not set
 CONFIG_RAMBASE=0x00000000
 CONFIG_RAMSIZE=0x00000000
@@ -39,24 +32,19 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_FEC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_PPP=y
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
 CONFIG_SERIAL_MCF=y
 CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_EXT2_FS=y
@@ -65,8 +53,5 @@ CONFIG_EXT2_FS=y
 CONFIG_ROMFS_FS=y
 CONFIG_ROMFS_BACKED_BY_MTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_BOOTPARAM=y
 CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
index 023812abd2e6c6d701015dd99f70693dd1eb7251..1b4c09461c409c195e1966012fd4bf1461f34ab6 100644 (file)
@@ -1,10 +1,6 @@
-# CONFIG_MMU is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -16,10 +12,8 @@ CONFIG_EXPERT=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
 CONFIG_M5307=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=90000000
-CONFIG_CLOCK_DIV=2
 CONFIG_M5307C3=y
 CONFIG_RAMBASE=0x00000000
 CONFIG_RAMSIZE=0x00800000
@@ -38,16 +32,11 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_PPP=y
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
@@ -56,21 +45,17 @@ CONFIG_SLIP_COMPRESSED=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MCF=y
 CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_LEGACY_PTYS 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_DNOTIFY is not set
 CONFIG_ROMFS_FS=y
 CONFIG_ROMFS_BACKED_BY_MTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_FULLDEBUG=y
 CONFIG_BOOTPARAM=y
 CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
+CONFIG_FULLDEBUG=y
index 557b39f3be9094e223fb8715cae927c0c5ba1cd3..275ad543d4bcbe0223a6837a7e093a488749a2f5 100644 (file)
@@ -1,10 +1,6 @@
-# CONFIG_MMU is not set
-CONFIG_EXPERIMENTAL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -17,9 +13,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MMU is not set
 CONFIG_M5407=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=50000000
 CONFIG_M5407C3=y
 CONFIG_RAMBASE=0x00000000
 CONFIG_RAMSIZE=0x00000000
@@ -38,22 +33,17 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
 CONFIG_PPP=y
 # CONFIG_INPUT is not set
 # CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
 CONFIG_SERIAL_MCF=y
 CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
@@ -63,8 +53,5 @@ CONFIG_EXT2_FS=y
 CONFIG_ROMFS_FS=y
 CONFIG_ROMFS_BACKED_BY_MTD=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_BOOTPARAM=y
 CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
index c5018a68819b5462b67544ee99606e8d4d333b4d..4f4ccd13c11bb164c1661d720b21d60c5226da6a 100644 (file)
@@ -1,11 +1,7 @@
-CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_SYSCTL_SYSCALL=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
@@ -20,19 +16,16 @@ CONFIG_MODULES=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_COLDFIRE=y
-CONFIG_M547x=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=266000000
 # CONFIG_4KSTACKS is not set
 CONFIG_RAMBASE=0x0
 CONFIG_RAMSIZE=0x2000000
 CONFIG_VECTORBASE=0x0
 CONFIG_MBAR=0xff000000
 CONFIG_KERNELBASE=0x20000
+CONFIG_PCI=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS 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_JEDECPROBE=y
index 1555bc189c7d65cfd8722e03dea2cd03d65109f4..eb85bd9c6180579bf119263bdce899045d10d375 100644 (file)
@@ -18,6 +18,7 @@ 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 += mutex.h
 generic-y += percpu.h
index c94557b914482dfa7d272eaf73e9aa0951c7354d..50aa4dac9ca28ba444ced005a251e9de54bfbd7d 100644 (file)
@@ -19,7 +19,7 @@
  *     in any case new boards come along from time to time that have yet
  *     another different clocking frequency.
  */
-#ifdef CONFIG_CLOCK_SET
+#ifdef CONFIG_CLOCK_FREQ
 #define        MCF_CLK         CONFIG_CLOCK_FREQ
 #else
 #error "Don't know what your ColdFire CPU clock frequency is??"
index 618c85d3c786713c8787043f176eac5d74e13e5e..f55cad529400f65eb38832cce8c96760a44f1aad 100644 (file)
@@ -413,7 +413,8 @@ static inline void isa_delay(void)
 #define writew(val, addr)      out_le16((addr), (val))
 #endif /* CONFIG_ATARI_ROM_ISA */
 
-#if !defined(CONFIG_ISA) && !defined(CONFIG_ATARI_ROM_ISA)
+#if !defined(CONFIG_ISA) && !defined(CONFIG_ATARI_ROM_ISA) && \
+    !(defined(CONFIG_PCI) && defined(CONFIG_COLDFIRE))
 /*
  * We need to define dummy functions for GENERIC_IOMAP support.
  */
diff --git a/arch/m68k/include/asm/mm-arch-hooks.h b/arch/m68k/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 7e8709b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_M68K_MM_ARCH_HOOKS_H
-#define _ASM_M68K_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_M68K_MM_ARCH_HOOKS_H */
index 199320f3c34528c09b392c391e2bcc0874d1f1d5..df31353fd2001dc0e357feafcf975aa6e5537622 100644 (file)
@@ -25,6 +25,7 @@ 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 += msgbuf.h
 generic-y += mutex.h
 generic-y += param.h
diff --git a/arch/metag/include/asm/mm-arch-hooks.h b/arch/metag/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index b0072b2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_METAG_MM_ARCH_HOOKS_H
-#define _ASM_METAG_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_METAG_MM_ARCH_HOOKS_H */
index 9989ddb169cab99c25433f2586f184015568a1ef..2f222f355c4bbc69842ccd62f3419b0cbd1732a4 100644 (file)
@@ -6,6 +6,7 @@ generic-y += device.h
 generic-y += exec.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += preempt.h
 generic-y += syscalls.h
 generic-y += trace_clock.h
diff --git a/arch/microblaze/include/asm/mm-arch-hooks.h b/arch/microblaze/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 5c40659..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_MICROBLAZE_MM_ARCH_HOOKS_H
-#define _ASM_MICROBLAZE_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_MICROBLAZE_MM_ARCH_HOOKS_H */
index 2a14585c90d254a645a3af9705c8aed12cfac099..199a8357838cb24bde2ce5ed5dec7db62feb8d2e 100644 (file)
@@ -151,7 +151,6 @@ config BMIPS_GENERIC
        select BCM7120_L2_IRQ
        select BRCMSTB_L2_IRQ
        select IRQ_MIPS_CPU
-       select RAW_IRQ_ACCESSORS
        select DMA_NONCOHERENT
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
@@ -1427,6 +1426,7 @@ config CPU_MIPS64_R6
        select CPU_SUPPORTS_HIGHMEM
        select CPU_SUPPORTS_MSA
        select GENERIC_CSUM
+       select MIPS_O32_FP64_SUPPORT if MIPS32_O32
        help
          Choose this option to build a kernel for release 6 or later of the
          MIPS64 architecture.  New MIPS processors, starting with the Warrior
@@ -2231,7 +2231,7 @@ config MIPS_CMP
 
 config MIPS_CPS
        bool "MIPS Coherent Processing System support"
-       depends on SYS_SUPPORTS_MIPS_CPS && !64BIT
+       depends on SYS_SUPPORTS_MIPS_CPS
        select MIPS_CM
        select MIPS_CPC
        select MIPS_CPS_PM if HOTPLUG_CPU
@@ -2262,11 +2262,6 @@ config MIPS_CM
 config MIPS_CPC
        bool
 
-config SB1_PASS_1_WORKAROUNDS
-       bool
-       depends on CPU_SB1_PASS_1
-       default y
-
 config SB1_PASS_2_WORKAROUNDS
        bool
        depends on CPU_SB1 && (CPU_SB1_PASS_2_2 || CPU_SB1_PASS_2)
index ae2dd59050f742c54c49b3f80925bbfc4e67fbbd..252e347958f383354a597323078512846f592d52 100644 (file)
@@ -181,13 +181,6 @@ cflags-$(CONFIG_CPU_R4000_WORKAROUNDS)     += $(call cc-option,-mfix-r4000,)
 cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,)
 cflags-$(CONFIG_CPU_DADDI_WORKAROUNDS) += $(call cc-option,-mno-daddi,)
 
-ifdef CONFIG_CPU_SB1
-ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-KBUILD_AFLAGS_MODULE += -msb1-pass1-workarounds
-KBUILD_CFLAGS_MODULE += -msb1-pass1-workarounds
-endif
-endif
-
 # For smartmips configurations, there are hundreds of warnings due to ISA overrides
 # in assembly and header files. smartmips is only supported for MIPS32r1 onwards
 # and there is no support for 64-bit. Various '.set mips2' or '.set mips3' or
index 01a644f174dd08e34843ca501035b077d777bea2..1ba21204ebe021ee164a9f8f4828dd3f3c836f84 100644 (file)
@@ -190,6 +190,7 @@ int get_c0_perfcount_int(void)
 {
        return ATH79_MISC_IRQ(5);
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 56f5d080ef9d6cb698ba70cf7027783167000284..b7fa9ae28c3659dbf457aecd7cd17255cd34f5da 100644 (file)
@@ -42,7 +42,7 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
        cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
 
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
index 7fe5c61a3cb83a0399bcd5e2745641f45eb08763..1f8546081d2068f3adaef34892354b9e6fb2119f 100644 (file)
@@ -7,6 +7,7 @@ generic-y += emergency-restart.h
 generic-y += irq_work.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += mutex.h
 generic-y += parport.h
 generic-y += percpu.h
index 084780b355aa51ee00fff050f49dab33b07d0f5d..1b062518983525f0065841c628b4ac10b047aeb2 100644 (file)
@@ -74,7 +74,7 @@ static inline int __enable_fpu(enum fpu_mode mode)
                goto fr_common;
 
        case FPU_64BIT:
-#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS32_R6) \
+#if !(defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) \
       || defined(CONFIG_64BIT))
                /* we only have a 32-bit FPU */
                return SIGFPE;
diff --git a/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h b/arch/mips/include/asm/mach-bcm63xx/dma-coherence.h
deleted file mode 100644 (file)
index 11d3b57..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-#define __ASM_MACH_BCM63XX_DMA_COHERENCE_H
-
-#include <asm/bmips.h>
-
-#define plat_post_dma_flush    bmips_post_dma_flush
-
-#include <asm/mach-generic/dma-coherence.h>
-
-#endif /* __ASM_MACH_BCM63XX_DMA_COHERENCE_H */
index 37c08a27b4f00a338d46d1fdbef718eac62809f1..c9f7e231e66bbe78a86412516bee7301b5cf8027 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
- *                    Insititute of Computing Technology
+ *                    Institute of Computing Technology
  * Author:  Xiang Gao, gaoxiang@ict.ac.cn
  *          Huacai Chen, chenhc@lemote.com
  *          Xiaofu Meng, Shuangshuang Zhang
index 0a227d426b9cbf5d284e8d523eba1939fd4d9294..520f8fc2c8067c7e3b77cd7cd03bd39a83586c11 100644 (file)
@@ -13,8 +13,7 @@
 #define R4600_V2_HIT_CACHEOP_WAR       0
 #define R5432_CP0_INTERRUPT_WAR                0
 
-#if defined(CONFIG_SB1_PASS_1_WORKAROUNDS) || \
-    defined(CONFIG_SB1_PASS_2_WORKAROUNDS)
+#if defined(CONFIG_SB1_PASS_2_WORKAROUNDS)
 
 #ifndef __ASSEMBLY__
 extern int sb1250_m3_workaround_needed(void);
diff --git a/arch/mips/include/asm/mm-arch-hooks.h b/arch/mips/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index b5609fe..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_MIPS_MM_ARCH_HOOKS_H
-#define _ASM_MIPS_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_MIPS_MM_ARCH_HOOKS_H */
index 9d810675814291d14ce004f9d4447678af2227c3..ae85694752644339af22557a5ae424cde8271400 100644 (file)
@@ -182,8 +182,39 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
                 * Make sure the buddy is global too (if it's !none,
                 * it better already be global)
                 */
+#ifdef CONFIG_SMP
+               /*
+                * For SMP, multiple CPUs can race, so we need to do
+                * this atomically.
+                */
+#ifdef CONFIG_64BIT
+#define LL_INSN "lld"
+#define SC_INSN "scd"
+#else /* CONFIG_32BIT */
+#define LL_INSN "ll"
+#define SC_INSN "sc"
+#endif
+               unsigned long page_global = _PAGE_GLOBAL;
+               unsigned long tmp;
+
+               __asm__ __volatile__ (
+                       "       .set    push\n"
+                       "       .set    noreorder\n"
+                       "1:     " LL_INSN "     %[tmp], %[buddy]\n"
+                       "       bnez    %[tmp], 2f\n"
+                       "        or     %[tmp], %[tmp], %[global]\n"
+                       "       " SC_INSN "     %[tmp], %[buddy]\n"
+                       "       beqz    %[tmp], 1b\n"
+                       "        nop\n"
+                       "2:\n"
+                       "       .set pop"
+                       : [buddy] "+m" (buddy->pte),
+                         [tmp] "=&r" (tmp)
+                       : [global] "r" (page_global));
+#else /* !CONFIG_SMP */
                if (pte_none(*buddy))
                        pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
+#endif /* CONFIG_SMP */
        }
 #endif
 }
index 2b25d1ba1ea037ca82212ec542a165e714ecf29c..03722d4326a1aad05935b58805ec8d881703201e 100644 (file)
@@ -23,6 +23,7 @@
 extern int smp_num_siblings;
 extern cpumask_t cpu_sibling_map[];
 extern cpumask_t cpu_core_map[];
+extern cpumask_t cpu_foreign_map;
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
@@ -82,8 +83,6 @@ static inline void __cpu_die(unsigned int cpu)
 extern void play_dead(void);
 #endif
 
-extern asmlinkage void smp_call_function_interrupt(void);
-
 static inline void arch_send_call_function_single_ipi(int cpu)
 {
        extern struct plat_smp_ops *mp_ops;     /* private */
index 28d6d9364bd1f2c431df08c72f58262e5297ec5c..a71da576883c8f4b1a3d60279ebfaefb95798031 100644 (file)
                .set    noreorder
                bltz    k0, 8f
                 move   k1, sp
+#ifdef CONFIG_EVA
+               /*
+                * Flush interAptiv's Return Prediction Stack (RPS) by writing
+                * EntryHi. Toggling Config7.RPS is slower and less portable.
+                *
+                * The RPS isn't automatically flushed when exceptions are
+                * taken, which can result in kernel mode speculative accesses
+                * to user addresses if the RPS mispredicts. That's harmless
+                * when user and kernel share the same address space, but with
+                * EVA the same user segments may be unmapped to kernel mode,
+                * even containing sensitive MMIO regions or invalid memory.
+                *
+                * This can happen when the kernel sets the return address to
+                * ret_from_* and jr's to the exception handler, which looks
+                * more like a tail call than a function call. If nested calls
+                * don't evict the last user address in the RPS, it will
+                * mispredict the return and fetch from a user controlled
+                * address into the icache.
+                *
+                * More recent EVA-capable cores with MAAR to restrict
+                * speculative accesses aren't affected.
+                */
+               MFC0    k0, CP0_ENTRYHI
+               MTC0    k0, CP0_ENTRYHI
+#endif
                .set    reorder
                /* Called from user mode, new stack. */
                get_saved_sp
index 6c9906f59c6e69f4a6d778064204c8764653b12a..9081d88ae44f31a1bf0c2e4d5c4ae1bdc0e487db 100644 (file)
@@ -16,7 +16,7 @@
 
 /*
  * Keep this struct definition in sync with the sigcontext fragment
- * in arch/mips/tools/offset.c
+ * in arch/mips/kernel/asm-offsets.c
  */
 struct sigcontext {
        unsigned int            sc_regmask;     /* Unused */
@@ -46,7 +46,7 @@ struct sigcontext {
 #include <linux/posix_types.h>
 /*
  * Keep this struct definition in sync with the sigcontext fragment
- * in arch/mips/tools/offset.c
+ * in arch/mips/kernel/asm-offsets.c
  *
  * Warning: this structure illdefined with sc_badvaddr being just an unsigned
  * int so it was changed to unsigned long in 2.6.0-test1.  This may break
index beabe19ff8e5c963af0cf38147a3f4b7af64efca..072fab13645d503a3b71381fec8c5976f570a905 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * offset.c: Calculate pt_regs and task_struct offsets.
+ * asm-offsets.c: Calculate pt_regs and task_struct offsets.
  *
  * Copyright (C) 1996 David S. Miller
  * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Ralf Baechle
index c0c5e5972256e95273d7e34a0b4c3c4132232cd0..d8f9b357b2226bef0141c8ed6340baa8fb7c0f4f 100644 (file)
@@ -600,7 +600,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                break;
 
        case blezl_op: /* not really i_format */
-               if (NO_R6EMU)
+               if (!insn.i_format.rt && NO_R6EMU)
                        goto sigill_r6;
        case blez_op:
                /*
@@ -635,7 +635,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                break;
 
        case bgtzl_op:
-               if (NO_R6EMU)
+               if (!insn.i_format.rt && NO_R6EMU)
                        goto sigill_r6;
        case bgtz_op:
                /*
index 55b759a0019e61671d78919bc5b143ba5ff4a94d..1b6ca634e6465b6fea48eaa81d45dec259e445e2 100644 (file)
@@ -60,7 +60,7 @@ LEAF(mips_cps_core_entry)
         nop
 
        /* This is an NMI */
-       la      k0, nmi_handler
+       PTR_LA  k0, nmi_handler
        jr      k0
         nop
 
@@ -107,10 +107,10 @@ not_nmi:
        mul     t1, t1, t0
        mul     t1, t1, t2
 
-       li      a0, KSEG0
-       add     a1, a0, t1
+       li      a0, CKSEG0
+       PTR_ADD a1, a0, t1
 1:     cache   Index_Store_Tag_I, 0(a0)
-       add     a0, a0, t0
+       PTR_ADD a0, a0, t0
        bne     a0, a1, 1b
         nop
 icache_done:
@@ -134,12 +134,12 @@ icache_done:
        mul     t1, t1, t0
        mul     t1, t1, t2
 
-       li      a0, KSEG0
-       addu    a1, a0, t1
-       subu    a1, a1, t0
+       li      a0, CKSEG0
+       PTR_ADDU a1, a0, t1
+       PTR_SUBU a1, a1, t0
 1:     cache   Index_Store_Tag_D, 0(a0)
        bne     a0, a1, 1b
-        add    a0, a0, t0
+        PTR_ADD a0, a0, t0
 dcache_done:
 
        /* Set Kseg0 CCA to that in s0 */
@@ -152,11 +152,11 @@ dcache_done:
 
        /* Enter the coherent domain */
        li      t0, 0xff
-       sw      t0, GCR_CL_COHERENCE_OFS(v1)
+       PTR_S   t0, GCR_CL_COHERENCE_OFS(v1)
        ehb
 
        /* Jump to kseg0 */
-       la      t0, 1f
+       PTR_LA  t0, 1f
        jr      t0
         nop
 
@@ -178,9 +178,9 @@ dcache_done:
         nop
 
        /* Off we go! */
-       lw      t1, VPEBOOTCFG_PC(v0)
-       lw      gp, VPEBOOTCFG_GP(v0)
-       lw      sp, VPEBOOTCFG_SP(v0)
+       PTR_L   t1, VPEBOOTCFG_PC(v0)
+       PTR_L   gp, VPEBOOTCFG_GP(v0)
+       PTR_L   sp, VPEBOOTCFG_SP(v0)
        jr      t1
         nop
        END(mips_cps_core_entry)
@@ -217,7 +217,7 @@ LEAF(excep_intex)
 
 .org 0x480
 LEAF(excep_ejtag)
-       la      k0, ejtag_debug_handler
+       PTR_LA  k0, ejtag_debug_handler
        jr      k0
         nop
        END(excep_ejtag)
@@ -229,7 +229,7 @@ LEAF(mips_cps_core_init)
         nop
 
        .set    push
-       .set    mips32r2
+       .set    mips64r2
        .set    mt
 
        /* Only allow 1 TC per VPE to execute... */
@@ -237,7 +237,7 @@ LEAF(mips_cps_core_init)
 
        /* ...and for the moment only 1 VPE */
        dvpe
-       la      t1, 1f
+       PTR_LA  t1, 1f
        jr.hb   t1
         nop
 
@@ -250,25 +250,25 @@ LEAF(mips_cps_core_init)
        mfc0    t0, CP0_MVPCONF0
        srl     t0, t0, MVPCONF0_PVPE_SHIFT
        andi    t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT)
-       addiu   t7, t0, 1
+       addiu   ta3, t0, 1
 
        /* If there's only 1, we're done */
        beqz    t0, 2f
         nop
 
        /* Loop through each VPE within this core */
-       li      t5, 1
+       li      ta1, 1
 
 1:     /* Operate on the appropriate TC */
-       mtc0    t5, CP0_VPECONTROL
+       mtc0    ta1, CP0_VPECONTROL
        ehb
 
        /* Bind TC to VPE (1:1 TC:VPE mapping) */
-       mttc0   t5, CP0_TCBIND
+       mttc0   ta1, CP0_TCBIND
 
        /* Set exclusive TC, non-active, master */
        li      t0, VPECONF0_MVP
-       sll     t1, t5, VPECONF0_XTC_SHIFT
+       sll     t1, ta1, VPECONF0_XTC_SHIFT
        or      t0, t0, t1
        mttc0   t0, CP0_VPECONF0
 
@@ -280,8 +280,8 @@ LEAF(mips_cps_core_init)
        mttc0   t0, CP0_TCHALT
 
        /* Next VPE */
-       addiu   t5, t5, 1
-       slt     t0, t5, t7
+       addiu   ta1, ta1, 1
+       slt     t0, ta1, ta3
        bnez    t0, 1b
         nop
 
@@ -298,19 +298,19 @@ LEAF(mips_cps_core_init)
 
 LEAF(mips_cps_boot_vpes)
        /* Retrieve CM base address */
-       la      t0, mips_cm_base
-       lw      t0, 0(t0)
+       PTR_LA  t0, mips_cm_base
+       PTR_L   t0, 0(t0)
 
        /* Calculate a pointer to this cores struct core_boot_config */
-       lw      t0, GCR_CL_ID_OFS(t0)
+       PTR_L   t0, GCR_CL_ID_OFS(t0)
        li      t1, COREBOOTCFG_SIZE
        mul     t0, t0, t1
-       la      t1, mips_cps_core_bootcfg
-       lw      t1, 0(t1)
-       addu    t0, t0, t1
+       PTR_LA  t1, mips_cps_core_bootcfg
+       PTR_L   t1, 0(t1)
+       PTR_ADDU t0, t0, t1
 
        /* Calculate this VPEs ID. If the core doesn't support MT use 0 */
-       has_mt  t6, 1f
+       has_mt  ta2, 1f
         li     t9, 0
 
        /* Find the number of VPEs present in the core */
@@ -334,24 +334,24 @@ LEAF(mips_cps_boot_vpes)
 1:     /* Calculate a pointer to this VPEs struct vpe_boot_config */
        li      t1, VPEBOOTCFG_SIZE
        mul     v0, t9, t1
-       lw      t7, COREBOOTCFG_VPECONFIG(t0)
-       addu    v0, v0, t7
+       PTR_L   ta3, COREBOOTCFG_VPECONFIG(t0)
+       PTR_ADDU v0, v0, ta3
 
 #ifdef CONFIG_MIPS_MT
 
        /* If the core doesn't support MT then return */
-       bnez    t6, 1f
+       bnez    ta2, 1f
         nop
        jr      ra
         nop
 
        .set    push
-       .set    mips32r2
+       .set    mips64r2
        .set    mt
 
 1:     /* Enter VPE configuration state */
        dvpe
-       la      t1, 1f
+       PTR_LA  t1, 1f
        jr.hb   t1
         nop
 1:     mfc0    t1, CP0_MVPCONTROL
@@ -360,12 +360,12 @@ LEAF(mips_cps_boot_vpes)
        ehb
 
        /* Loop through each VPE */
-       lw      t6, COREBOOTCFG_VPEMASK(t0)
-       move    t8, t6
-       li      t5, 0
+       PTR_L   ta2, COREBOOTCFG_VPEMASK(t0)
+       move    t8, ta2
+       li      ta1, 0
 
        /* Check whether the VPE should be running. If not, skip it */
-1:     andi    t0, t6, 1
+1:     andi    t0, ta2, 1
        beqz    t0, 2f
         nop
 
@@ -373,7 +373,7 @@ LEAF(mips_cps_boot_vpes)
        mfc0    t0, CP0_VPECONTROL
        ori     t0, t0, VPECONTROL_TARGTC
        xori    t0, t0, VPECONTROL_TARGTC
-       or      t0, t0, t5
+       or      t0, t0, ta1
        mtc0    t0, CP0_VPECONTROL
        ehb
 
@@ -384,8 +384,8 @@ LEAF(mips_cps_boot_vpes)
 
        /* Calculate a pointer to the VPEs struct vpe_boot_config */
        li      t0, VPEBOOTCFG_SIZE
-       mul     t0, t0, t5
-       addu    t0, t0, t7
+       mul     t0, t0, ta1
+       addu    t0, t0, ta3
 
        /* Set the TC restart PC */
        lw      t1, VPEBOOTCFG_PC(t0)
@@ -423,9 +423,9 @@ LEAF(mips_cps_boot_vpes)
        mttc0   t0, CP0_VPECONF0
 
        /* Next VPE */
-2:     srl     t6, t6, 1
-       addiu   t5, t5, 1
-       bnez    t6, 1b
+2:     srl     ta2, ta2, 1
+       addiu   ta1, ta1, 1
+       bnez    ta2, 1b
         nop
 
        /* Leave VPE configuration state */
@@ -445,7 +445,7 @@ LEAF(mips_cps_boot_vpes)
        /* This VPE should be offline, halt the TC */
        li      t0, TCHALT_H
        mtc0    t0, CP0_TCHALT
-       la      t0, 1f
+       PTR_LA  t0, 1f
 1:     jr.hb   t0
         nop
 
@@ -466,10 +466,10 @@ LEAF(mips_cps_boot_vpes)
        .set    noat
        lw      $1, TI_CPU(gp)
        sll     $1, $1, LONGLOG
-       la      \dest, __per_cpu_offset
+       PTR_LA  \dest, __per_cpu_offset
        addu    $1, $1, \dest
        lw      $1, 0($1)
-       la      \dest, cps_cpu_state
+       PTR_LA  \dest, cps_cpu_state
        addu    \dest, \dest, $1
        .set    pop
        .endm
index af42e7003f12d025cd31e2a5d167f2f4b158d37a..baa7b6fc0a60b1879976c2d4158f73d01e0ca53b 100644 (file)
@@ -407,7 +407,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
        .set    noat
        SAVE_ALL
        FEXPORT(handle_\exception\ext)
-       __BUILD_clear_\clear
+       __build_clear_\clear
        .set    at
        __BUILD_\verbose \exception
        move    a0, sp
index 3e4491aa6d6b2425865e1d1a3a909cf05aaa4e28..789d7bf4fef3203b3038a9ddaf20c5f70f1bc948 100644 (file)
@@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
                                      unsigned long __user *user_mask_ptr)
 {
        unsigned int real_len;
-       cpumask_t mask;
+       cpumask_t allowed, mask;
        int retval;
        struct task_struct *p;
 
@@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
        if (retval)
                goto out_unlock;
 
-       cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask);
+       cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed);
+       cpumask_and(&mask, &allowed, cpu_active_mask);
 
 out_unlock:
        read_unlock(&tasklist_lock);
index b130033838ba0c391ef4f9f0c7aa19e5a50b6eb7..5fcec3032f38f6aebdf668af3318997e4f53921f 100644 (file)
@@ -38,7 +38,7 @@ char *mips_get_machine_name(void)
        return mips_machine_name;
 }
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_USE_OF
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
        return add_memory_region(base, size, BOOT_MEM_RAM);
index 74bab9ddd0e1984c9d4e4e95c038bb1d269b60dd..c6bbf21650515d1e71eead45b41a7729f8794476 100644 (file)
@@ -24,7 +24,7 @@ LEAF(relocate_new_kernel)
 
 process_entry:
        PTR_L           s2, (s0)
-       PTR_ADD         s0, s0, SZREG
+       PTR_ADDIU       s0, s0, SZREG
 
        /*
         * In case of a kdump/crash kernel, the indirection page is not
@@ -61,9 +61,9 @@ copy_word:
        /* copy page word by word */
        REG_L           s5, (s2)
        REG_S           s5, (s4)
-       PTR_ADD         s4, s4, SZREG
-       PTR_ADD         s2, s2, SZREG
-       LONG_SUB        s6, s6, 1
+       PTR_ADDIU       s4, s4, SZREG
+       PTR_ADDIU       s2, s2, SZREG
+       LONG_ADDIU      s6, s6, -1
        beq             s6, zero, process_entry
        b               copy_word
        b               process_entry
index 6e8de80bb4468c82378d3c4af8ef3d08cefd5cf1..4cc13508d967c4076e0b720b120487281003ed72 100644 (file)
@@ -73,10 +73,11 @@ NESTED(handle_sys, PT_SIZE, sp)
        .set    noreorder
        .set    nomacro
 
-1:     user_lw(t5, 16(t0))             # argument #5 from usp
-4:     user_lw(t6, 20(t0))             # argument #6 from usp
-3:     user_lw(t7, 24(t0))             # argument #7 from usp
-2:     user_lw(t8, 28(t0))             # argument #8 from usp
+load_a4: user_lw(t5, 16(t0))           # argument #5 from usp
+load_a5: user_lw(t6, 20(t0))           # argument #6 from usp
+load_a6: user_lw(t7, 24(t0))           # argument #7 from usp
+load_a7: user_lw(t8, 28(t0))           # argument #8 from usp
+loads_done:
 
        sw      t5, 16(sp)              # argument #5 to ksp
        sw      t6, 20(sp)              # argument #6 to ksp
@@ -85,10 +86,10 @@ NESTED(handle_sys, PT_SIZE, sp)
        .set    pop
 
        .section __ex_table,"a"
-       PTR     1b,bad_stack
-       PTR     2b,bad_stack
-       PTR     3b,bad_stack
-       PTR     4b,bad_stack
+       PTR     load_a4, bad_stack_a4
+       PTR     load_a5, bad_stack_a5
+       PTR     load_a6, bad_stack_a6
+       PTR     load_a7, bad_stack_a7
        .previous
 
        lw      t0, TI_FLAGS($28)       # syscall tracing enabled?
@@ -153,8 +154,8 @@ syscall_trace_entry:
 /* ------------------------------------------------------------------------ */
 
        /*
-        * The stackpointer for a call with more than 4 arguments is bad.
-        * We probably should handle this case a bit more drastic.
+        * Our open-coded access area sanity test for the stack pointer
+        * failed. We probably should handle this case a bit more drastic.
         */
 bad_stack:
        li      v0, EFAULT
@@ -163,6 +164,22 @@ bad_stack:
        sw      t0, PT_R7(sp)
        j       o32_syscall_exit
 
+bad_stack_a4:
+       li      t5, 0
+       b       load_a5
+
+bad_stack_a5:
+       li      t6, 0
+       b       load_a6
+
+bad_stack_a6:
+       li      t7, 0
+       b       load_a7
+
+bad_stack_a7:
+       li      t8, 0
+       b       loads_done
+
        /*
         * The system call does not exist in this kernel
         */
index ad4d44635c7601162ca0dd8f1b626df28eeeafb2..a6f6b762c47a4c5a2d395e13a1d564964595abe1 100644 (file)
@@ -80,7 +80,7 @@ syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       daddiu  a1, v0, __NR_64_Linux
+       move    a1, v0
        jal     syscall_trace_enter
 
        bltz    v0, 2f                  # seccomp failed? Skip syscall
index 446cc654da56c5f5fcaad749242dd98d593776e1..4b2010654c463158b7dee80194de736195c04595 100644 (file)
@@ -72,7 +72,7 @@ n32_syscall_trace_entry:
        SAVE_STATIC
        move    s0, t2
        move    a0, sp
-       daddiu  a1, v0, __NR_N32_Linux
+       move    a1, v0
        jal     syscall_trace_enter
 
        bltz    v0, 2f                  # seccomp failed? Skip syscall
index d07b210fbeff3667f49737dbec9d9d30d3f119ed..f543ff4feef99f8c4ce02554f4dd54da1752b6de 100644 (file)
@@ -69,16 +69,17 @@ NESTED(handle_sys, PT_SIZE, sp)
        daddu   t1, t0, 32
        bltz    t1, bad_stack
 
-1:     lw      a4, 16(t0)              # argument #5 from usp
-2:     lw      a5, 20(t0)              # argument #6 from usp
-3:     lw      a6, 24(t0)              # argument #7 from usp
-4:     lw      a7, 28(t0)              # argument #8 from usp (for indirect syscalls)
+load_a4: lw    a4, 16(t0)              # argument #5 from usp
+load_a5: lw    a5, 20(t0)              # argument #6 from usp
+load_a6: lw    a6, 24(t0)              # argument #7 from usp
+load_a7: lw    a7, 28(t0)              # argument #8 from usp
+loads_done:
 
        .section __ex_table,"a"
-       PTR     1b, bad_stack
-       PTR     2b, bad_stack
-       PTR     3b, bad_stack
-       PTR     4b, bad_stack
+       PTR     load_a4, bad_stack_a4
+       PTR     load_a5, bad_stack_a5
+       PTR     load_a6, bad_stack_a6
+       PTR     load_a7, bad_stack_a7
        .previous
 
        li      t1, _TIF_WORK_SYSCALL_ENTRY
@@ -167,6 +168,22 @@ bad_stack:
        sd      t0, PT_R7(sp)
        j       o32_syscall_exit
 
+bad_stack_a4:
+       li      a4, 0
+       b       load_a5
+
+bad_stack_a5:
+       li      a5, 0
+       b       load_a6
+
+bad_stack_a6:
+       li      a6, 0
+       b       load_a7
+
+bad_stack_a7:
+       li      a7, 0
+       b       loads_done
+
 not_o32_scall:
        /*
         * This is not an o32 compatibility syscall, pass it on
@@ -383,7 +400,7 @@ EXPORT(sys32_call_table)
        PTR     sys_connect                     /* 4170 */
        PTR     sys_getpeername
        PTR     sys_getsockname
-       PTR     sys_getsockopt
+       PTR     compat_sys_getsockopt
        PTR     sys_listen
        PTR     compat_sys_recv                 /* 4175 */
        PTR     compat_sys_recvfrom
index be73c491182bcab53f74aa765498d4a026a5b71b..008b3378653a004b5cd2890445b6d23c250ca1f5 100644 (file)
@@ -337,6 +337,11 @@ static void __init bootmem_init(void)
                        min_low_pfn = start;
                if (end <= reserved_end)
                        continue;
+#ifdef CONFIG_BLK_DEV_INITRD
+               /* mapstart should be after initrd_end */
+               if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end)))
+                       continue;
+#endif
                if (start >= mapstart)
                        continue;
                mapstart = max(reserved_end, start);
@@ -366,14 +371,6 @@ static void __init bootmem_init(void)
                max_low_pfn = PFN_DOWN(HIGHMEM_START);
        }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-       /*
-        * mapstart should be after initrd_end
-        */
-       if (initrd_end)
-               mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end)));
-#endif
-
        /*
         * Initialize the boot-time allocator with low memory only.
         */
index 19a7705f2a015ef4b38e1cd0a16eb22c2a2d3ca3..5d7f2634996fd4920f0a4c94e00cd42fae5934b1 100644 (file)
@@ -409,8 +409,6 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
 
 int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, 3*sizeof(int)) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE32))
index 336708ae5c5b4c74b75416058feabb4bef5e30b1..78cf8c2f1de0e8790923d25ab6e42a85e53a6fe9 100644 (file)
@@ -284,7 +284,7 @@ static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
        if (action == 0)
                scheduler_ipi();
        else
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
@@ -336,7 +336,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
        if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+               generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 4251d390b5b66e0c20a7271659a280e448ca0ffe..c88937745b4ea18c7faf699f936f00cd42f9372d 100644 (file)
@@ -133,7 +133,7 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
        /*
         * Patch the start of mips_cps_core_entry to provide:
         *
-        * v0 = CM base address
+        * v1 = CM base address
         * s0 = kseg0 CCA
         */
        entry_code = (u32 *)&mips_cps_core_entry;
@@ -369,7 +369,7 @@ void play_dead(void)
 
 static void wait_for_sibling_halt(void *ptr_cpu)
 {
-       unsigned cpu = (unsigned)ptr_cpu;
+       unsigned cpu = (unsigned long)ptr_cpu;
        unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
        unsigned halted;
        unsigned long flags;
@@ -430,7 +430,7 @@ static void cps_cpu_die(unsigned int cpu)
                 */
                err = smp_call_function_single(cpu_death_sibling,
                                               wait_for_sibling_halt,
-                                              (void *)cpu, 1);
+                                              (void *)(unsigned long)cpu, 1);
                if (err)
                        panic("Failed to call remote sibling CPU\n");
        }
index faa46ebd9ddae2fc43f20d6ff65f28688f665c4f..a31896c33716d424bb30397c17b29af07c6728bb 100644 (file)
@@ -63,6 +63,13 @@ EXPORT_SYMBOL(cpu_sibling_map);
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_core_map);
 
+/*
+ * A logcal cpu mask containing only one VPE per core to
+ * reduce the number of IPIs on large MT systems.
+ */
+cpumask_t cpu_foreign_map __read_mostly;
+EXPORT_SYMBOL(cpu_foreign_map);
+
 /* representing cpus for which sibling maps can be computed */
 static cpumask_t cpu_sibling_setup_map;
 
@@ -103,6 +110,29 @@ static inline void set_cpu_core_map(int cpu)
        }
 }
 
+/*
+ * Calculate a new cpu_foreign_map mask whenever a
+ * new cpu appears or disappears.
+ */
+static inline void calculate_cpu_foreign_map(void)
+{
+       int i, k, core_present;
+       cpumask_t temp_foreign_map;
+
+       /* Re-calculate the mask */
+       for_each_online_cpu(i) {
+               core_present = 0;
+               for_each_cpu(k, &temp_foreign_map)
+                       if (cpu_data[i].package == cpu_data[k].package &&
+                           cpu_data[i].core == cpu_data[k].core)
+                               core_present = 1;
+               if (!core_present)
+                       cpumask_set_cpu(i, &temp_foreign_map);
+       }
+
+       cpumask_copy(&cpu_foreign_map, &temp_foreign_map);
+}
+
 struct plat_smp_ops *mp_ops;
 EXPORT_SYMBOL(mp_ops);
 
@@ -146,6 +176,8 @@ asmlinkage void start_secondary(void)
        set_cpu_sibling_map(cpu);
        set_cpu_core_map(cpu);
 
+       calculate_cpu_foreign_map();
+
        cpumask_set_cpu(cpu, &cpu_callin_map);
 
        synchronise_count_slave(cpu);
@@ -160,22 +192,21 @@ asmlinkage void start_secondary(void)
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
-/*
- * Call into both interrupt handlers, as we share the IPI for them
- */
-void __irq_entry smp_call_function_interrupt(void)
-{
-       irq_enter();
-       generic_smp_call_function_interrupt();
-       irq_exit();
-}
-
 static void stop_this_cpu(void *dummy)
 {
        /*
-        * Remove this CPU:
+        * Remove this CPU. Be a bit slow here and
+        * set the bits for every online CPU so we don't miss
+        * any IPI whilst taking this VPE down.
         */
+
+       cpumask_copy(&cpu_foreign_map, cpu_online_mask);
+
+       /* Make it visible to every other CPU */
+       smp_mb();
+
        set_cpu_online(smp_processor_id(), false);
+       calculate_cpu_foreign_map();
        local_irq_disable();
        while (1);
 }
@@ -197,6 +228,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        mp_ops->prepare_cpus(max_cpus);
        set_cpu_sibling_map(0);
        set_cpu_core_map(0);
+       calculate_cpu_foreign_map();
 #ifndef CONFIG_HOTPLUG_CPU
        init_cpu_present(cpu_possible_mask);
 #endif
index 2a7b38ed23f06e817bba6187b8890b98489e168d..8ea28e6ab37dead56439dc37871b6b18e8ec02d5 100644 (file)
@@ -192,6 +192,7 @@ static void show_stacktrace(struct task_struct *task,
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
        struct pt_regs regs;
+       mm_segment_t old_fs = get_fs();
        if (sp) {
                regs.regs[29] = (unsigned long)sp;
                regs.regs[31] = 0;
@@ -210,7 +211,13 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                        prepare_frametrace(&regs);
                }
        }
+       /*
+        * show_stack() deals exclusively with kernel mode, so be sure to access
+        * the stack in the kernel (not user) address space.
+        */
+       set_fs(KERNEL_DS);
        show_stacktrace(task, &regs);
+       set_fs(old_fs);
 }
 
 static void show_code(unsigned int __user *pc)
@@ -1519,6 +1526,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
        const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
        enum ctx_state prev_state;
+       mm_segment_t old_fs = get_fs();
 
        prev_state = exception_enter();
        show_regs(regs);
@@ -1540,8 +1548,13 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
                dump_tlb_all();
        }
 
+       if (!user_mode(regs))
+               set_fs(KERNEL_DS);
+
        show_code((unsigned int __user *) regs->cp0_epc);
 
+       set_fs(old_fs);
+
        /*
         * Some chips may have other causes of machine check (e.g. SB1
         * graduation timer)
@@ -2130,10 +2143,10 @@ void per_cpu_trap_init(bool is_boot_cpu)
        BUG_ON(current->mm);
        enter_lazy_tlb(&init_mm, current);
 
-               /* Boot CPU's cache setup in setup_arch(). */
-               if (!is_boot_cpu)
-                       cpu_cache_init();
-               tlb_init();
+       /* Boot CPU's cache setup in setup_arch(). */
+       if (!is_boot_cpu)
+               cpu_cache_init();
+       tlb_init();
        TLBMISS_HANDLER_SETUP();
 }
 
index af84bef0c90de4bc65e14669dca132ebb7147846..eb3efd137fd17cdb6e1defa163744a480ad16185 100644 (file)
@@ -438,7 +438,7 @@ do {                                                        \
                : "memory");                                \
 } while(0)
 
-#define     StoreDW(addr, value, res) \
+#define     _StoreDW(addr, value, res) \
 do {                                                        \
                __asm__ __volatile__ (                      \
                        ".set\tpush\n\t"                    \
index 6ab10573490de8a2d5a449e45c3585547c51f7c4..2c218c3bbca57be3d029cdb3320b712092bccd46 100644 (file)
@@ -293,7 +293,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
@@ -466,6 +466,7 @@ int get_c0_perfcount_int(void)
 {
        return ltq_perfcount_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index cc0e4fd548e64f46642c56eb38cea7b8d6480e7e..4e116d23bab38f0130ef566e561cdde26c30a979 100644 (file)
@@ -3,7 +3,7 @@
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
  *
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Fuxin Zhang, zhangfx@lemote.com
  *
  *  This program is free software; you can redistribute         it and/or modify it
index 72fed003a536d65e2676204753a6fa764f8e8b29..01fbed1370289a06d4440aacfad61c5e6ab77776 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2003 ICT CAS
  * Author: Michael Guo <guoyi@ict.ac.cn>
  *
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Fuxin Zhang, zhangfx@lemote.com
  *
  * Copyright (C) 2009 Lemote Inc.
index 12c75db23420c70fd5ff7837a78554f15cecd606..875037063a80ecc634d74759ce3032b78261ea19 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * CS5536 General timer functions
  *
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Yanhua, yanh@lemote.com
  *
  * Copyright (C) 2009 Lemote Inc.
index 22f04ca2ff3e58cd9ddddfa1ded6d84e5147efa0..f6c44dd332e2a388d28e5882a0c47e84ed3ca3f9 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2003 ICT CAS
  * Author: Michael Guo <guoyi@ict.ac.cn>
  *
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Fuxin Zhang, zhangfx@lemote.com
  *
  * Copyright (C) 2009 Lemote Inc.
index 687003b19b4546b77e0752031c4fcf918c037454..d36d969a4a878b66a50eda926158b047fdf53ef6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Fuxin Zhang, zhangfx@lemote.com
  *
  *  This program is free software; you can redistribute         it and/or modify it
index d477dd6bb3269cc9246def13db444f0628f1ce4c..2dc5122f0e09a454f3ade53a87eaf32f806b12ec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Fuxin Zhang, zhangfx@lemote.com
  *
  *  This program is free software; you can redistribute         it and/or modify it
index ef5ec8f3de5f2080588a41ec7ad8a495e4fa070c..892963f860b7a21e4b2f4cfa521a6a514d52f347 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
  * Author: Fuxin Zhang, zhangfx@lemote.com
  *
  *  This program is free software; you can redistribute         it and/or modify it
index 462e34d46b4a9fa2265532474ecda20d249e3f79..a78fb657068cb39fc785e241f9b70aeaa412a09b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology
  * Author: Yanhua, yanh@lemote.com
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -15,7 +15,7 @@
 #include <linux/spinlock.h>
 
 #include <asm/clock.h>
-#include <asm/mach-loongson/loongson.h>
+#include <asm/mach-loongson64/loongson.h>
 
 static LIST_HEAD(clock_list);
 static DEFINE_SPINLOCK(clock_lock);
index 12d14ed4877868abce36029ddad6df1b94339dba..6f9e010cec4d50f2cae8177c41d9ae95e0189b22 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
- *                    Insititute of Computing Technology
+ *                    Institute of Computing Technology
  * Author:  Xiang Gao, gaoxiang@ict.ac.cn
  *          Huacai Chen, chenhc@lemote.com
  *          Xiaofu Meng, Shuangshuang Zhang
index 509877c6e9d908d7bac6110982c7208ab69204af..1a4738a8f2d3906ccffb58bdf8d9b35ee4b04ef3 100644 (file)
@@ -266,8 +266,11 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 
        if (action & SMP_ASK_C0COUNT) {
                BUG_ON(cpu != 0);
index 22b9b2cb9219fa4e4eb7b9cc340125a4c9aa4053..712f17a2ecf206e1b5d33a63956e62baac29cb08 100644 (file)
@@ -451,7 +451,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        /* Fall through */
                case jr_op:
                        /* For R6, JR already emulated in jalr_op */
-                       if (NO_R6EMU && insn.r_format.opcode == jr_op)
+                       if (NO_R6EMU && insn.r_format.func == jr_op)
                                break;
                        *contpc = regs->regs[insn.r_format.rs];
                        return 1;
@@ -551,7 +551,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.next_pc_inc;
                return 1;
        case blezl_op:
-               if (NO_R6EMU)
+               if (!insn.i_format.rt && NO_R6EMU)
                        break;
        case blez_op:
 
@@ -588,7 +588,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.next_pc_inc;
                return 1;
        case bgtzl_op:
-               if (NO_R6EMU)
+               if (!insn.i_format.rt && NO_R6EMU)
                        break;
        case bgtz_op:
                /*
index 7f660dc67596e625cd65dc9f0980735d321a05dc..fbea4432f3f23fe3d44d278f48d28fd78797d580 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/cacheflush.h> /* for run_uncached() */
 #include <asm/traps.h>
 #include <asm/dma-coherence.h>
+#include <asm/mips-cm.h>
 
 /*
  * Special Variant of smp_call_function for use by cache functions:
@@ -51,9 +52,16 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
 {
        preempt_disable();
 
-#ifndef CONFIG_MIPS_MT_SMP
-       smp_call_function(func, info, 1);
-#endif
+       /*
+        * The Coherent Manager propagates address-based cache ops to other
+        * cores but not index-based ops. However, r4k_on_each_cpu is used
+        * in both cases so there is no easy way to tell what kind of op is
+        * executed to the other cores. The best we can probably do is
+        * to restrict that call when a CM is not present because both
+        * CM-based SMP protocols (CMP & CPS) restrict index-based cache ops.
+        */
+       if (!mips_cm_present())
+               smp_call_function_many(&cpu_foreign_map, func, info, 1);
        func(info);
        preempt_enable();
 }
@@ -937,7 +945,9 @@ static void b5k_instruction_hazard(void)
 }
 
 static char *way_string[] = { NULL, "direct mapped", "2-way",
-       "3-way", "4-way", "5-way", "6-way", "7-way", "8-way"
+       "3-way", "4-way", "5-way", "6-way", "7-way", "8-way",
+       "9-way", "10-way", "11-way", "12-way",
+       "13-way", "14-way", "15-way", "16-way",
 };
 
 static void probe_pcache(void)
index 77d96db8253c422ac9e48d93e02c6b6f39b41c1b..aab218c36e0d3e2f7669c47343e583e527103169 100644 (file)
@@ -160,18 +160,18 @@ static inline void setup_protection_map(void)
                protection_map[1]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
                protection_map[2]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
                protection_map[3]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
-               protection_map[4]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[4]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[5]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
-               protection_map[6]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[6]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[7]  = __pgprot(_page_cachable_default | _PAGE_PRESENT);
 
                protection_map[8]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_NO_READ);
                protection_map[9]  = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC);
                protection_map[10] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE | _PAGE_NO_READ);
                protection_map[11] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_EXEC | _PAGE_WRITE);
-               protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_NO_READ);
+               protection_map[12] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
                protection_map[13] = __pgprot(_page_cachable_default | _PAGE_PRESENT);
-               protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE  | _PAGE_NO_READ);
+               protection_map[14] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
                protection_map[15] = __pgprot(_page_cachable_default | _PAGE_PRESENT | _PAGE_WRITE);
 
        } else {
index 36c0f26fac6b0780318958a59fc2665a444a10ea..852a41c6da4507080d611dce0b1fc206caf30556 100644 (file)
@@ -133,7 +133,8 @@ good_area:
 #endif
                                goto bad_area;
                        }
-                       if (!(vma->vm_flags & VM_READ)) {
+                       if (!(vma->vm_flags & VM_READ) &&
+                           exception_epc(regs) != address) {
 #if 0
                                pr_notice("Cpu%d[%s:%d:%0*lx:%ld:%0*lx] RI violation\n",
                                          raw_smp_processor_id(),
index d1392f8f5811f65ec72445026ac12c4fe15fe6b1..fa8f591f371361ba6fe3654617e6f44690a48a25 100644 (file)
@@ -222,7 +222,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 185e68261f45937eae2b17dcd502420ce0121f69..b7bf721eabf5411bfb2f55b6b7d2cdc9ba887f96 100644 (file)
@@ -119,18 +119,24 @@ void read_persistent_clock(struct timespec *ts)
 
 int get_c0_fdc_int(void)
 {
-       int mips_cpu_fdc_irq;
+       /*
+        * Some cores claim the FDC is routable through the GIC, but it doesn't
+        * actually seem to be connected for those Malta bitstreams.
+        */
+       switch (current_cpu_type()) {
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
+               return -1;
+       };
 
        if (cpu_has_veic)
-               mips_cpu_fdc_irq = -1;
+               return -1;
        else if (gic_present)
-               mips_cpu_fdc_irq = gic_get_c0_fdc_int();
+               return gic_get_c0_fdc_int();
        else if (cp0_fdc_irq >= 0)
-               mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
+               return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
        else
-               mips_cpu_fdc_irq = -1;
-
-       return mips_cpu_fdc_irq;
+               return -1;
 }
 
 int get_c0_perfcount_int(void)
@@ -148,6 +154,7 @@ int get_c0_perfcount_int(void)
 
        return mips_cpu_perf_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
@@ -165,14 +172,17 @@ unsigned int get_c0_compare_int(void)
 
 static void __init init_rtc(void)
 {
-       /* stop the clock whilst setting it up */
-       CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL);
+       unsigned char freq, ctrl;
 
-       /* 32KHz time base */
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
+       /* Set 32KHz time base if not already set */
+       freq = CMOS_READ(RTC_FREQ_SELECT);
+       if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
+               CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
 
-       /* start the clock */
-       CMOS_WRITE(RTC_24H, RTC_CONTROL);
+       /* Ensure SET bit is clear so RTC can run */
+       ctrl = CMOS_READ(RTC_CONTROL);
+       if (ctrl & RTC_SET)
+               CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
 }
 
 void __init plat_time_init(void)
index e1d69895fb1de44f5d8503027f86ebb50f40d5a6..a120b7a5a8fe4e9af03ccb40fc9e7e123f88d633 100644 (file)
@@ -77,6 +77,7 @@ int get_c0_perfcount_int(void)
                return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
        return -1;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index dc3e327fbbac105e71c6b89a039e0f79f91e6f3d..f5fff228b347b6da07d68212fb11f4ae140548c8 100644 (file)
@@ -86,7 +86,7 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
 {
        clear_c0_eimr(irq);
        ack_c0_eirr(irq);
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        set_c0_eimr(irq);
 }
 
index 42181c7105df70992892ead68933bcd5375ab74b..f8d3e081b2ebc77e6752dc10a61a69e9a8172b3d 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t paravirt_reched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t paravirt_function_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
index d2dc836523a3dc917b4686dc662d07a9cc576b73..8bd8ebb20a72631501e5365478d10aa0d07b992b 100644 (file)
@@ -63,13 +63,19 @@ void __init plat_mem_setup(void)
        plat_setup_iocoherency();
 }
 
-#define DEFAULT_CPC_BASE_ADDR 0x1bde0000
+#define DEFAULT_CPC_BASE_ADDR  0x1bde0000
+#define DEFAULT_CDMM_BASE_ADDR 0x1bdd0000
 
 phys_addr_t mips_cpc_default_phys_base(void)
 {
        return DEFAULT_CPC_BASE_ADDR;
 }
 
+phys_addr_t mips_cdmm_phys_base(void)
+{
+       return DEFAULT_CDMM_BASE_ADDR;
+}
+
 static void __init mips_nmi_setup(void)
 {
        void *base;
index 67889fcea8aa8f27c9e3e4bf7249b6a0ec497ff9..8a377346f0cabbf5ce91199ca039ec013b16dda1 100644 (file)
@@ -26,6 +26,12 @@ int get_c0_perfcount_int(void)
 {
        return gic_get_c0_perfcount_int();
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
+
+int get_c0_fdc_int(void)
+{
+       return gic_get_c0_fdc_int();
+}
 
 void __init plat_time_init(void)
 {
index 10170580a2def4501bb4f149c707d050a900246f..ffa0f7101a9773ec8e24813f37e3c270d912b5e2 100644 (file)
@@ -44,7 +44,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index 53707aacc0f86cb13134546de07ccaf71d76321d..8c624a8b9ea29f5611abceb531de09c865e46b7c 100644 (file)
@@ -89,6 +89,7 @@ int get_c0_perfcount_int(void)
 {
        return rt_perfcount_irq;
 }
+EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
 
 unsigned int get_c0_compare_int(void)
 {
index 3fbaef97a1b8d31791e8999bd222e3e1b01c3701..16ec4e12daa3fb7bed3355a5cd56cdb3c87946fc 100644 (file)
@@ -107,10 +107,14 @@ static void ip27_do_irq_mask0(void)
                scheduler_ipi();
        } else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
                LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
-               smp_call_function_interrupt();
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
        } else
 #endif
        {
index a8bb972fd9fddfee74c791b750707970341861fc..cb9a095f5c5ec082188d21b96619c4fcb5fda7a0 100644 (file)
@@ -81,11 +81,6 @@ choice
        prompt "SiByte SOC Stepping"
        depends on SIBYTE_SB1xxx_SOC
 
-config CPU_SB1_PASS_1
-       bool "1250 Pass1"
-       depends on SIBYTE_SB1250
-       select CPU_HAS_PREFETCH
-
 config CPU_SB1_PASS_2_1250
        bool "1250 An"
        depends on SIBYTE_SB1250
index af7d44edd9a8f118b79944ecf21310634f308b56..4c71aea2566372c3f3af8627c79e91fb9aede4ea 100644 (file)
@@ -29,8 +29,6 @@
 #include <asm/sibyte/bcm1480_regs.h>
 #include <asm/sibyte/bcm1480_int.h>
 
-extern void smp_call_function_interrupt(void);
-
 /*
  * These are routines for dealing with the bcm1480 smp capabilities
  * independent of board/firmware
@@ -184,6 +182,9 @@ void bcm1480_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index 5581844c9194bc85719554789b58f1121c711eca..41a1d22422112caa5b08cbc51b66ca47cf267a72 100644 (file)
@@ -81,10 +81,7 @@ void check_bus_watcher(void)
 {
        u32 status, l2_err, memio_err;
 
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-       /* Destructive read, clears register and interrupt */
-       status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
-#elif defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
+#if defined(CONFIG_SIBYTE_BCM112X) || defined(CONFIG_SIBYTE_SB1250)
        /* Use non-destructive register */
        status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS_DEBUG));
 #elif defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
index 3c02b2a77ae996b0d84ebe085fe697d6879cb144..9d3c24efdf4a338aeb83fe16566ae5045e506e33 100644 (file)
@@ -202,12 +202,10 @@ void __init sb1250_setup(void)
 
        switch (war_pass) {
        case K_SYS_REVISION_BCM1250_PASS1:
-#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
                printk("@@@@ This is a BCM1250 A0-A2 (Pass 1) board, "
                            "and the kernel doesn't have the proper "
                            "workarounds compiled in. @@@@\n");
                bad_config = 1;
-#endif
                break;
        case K_SYS_REVISION_BCM1250_PASS2:
                /* Pass 2 - easiest as default for now - so many numbers */
index c0c4b3f88a086f2c331cce0b311d9c547d3b5a6a..1cf66f5ff23d1a5afca26ffd9bc638566d8f68cb 100644 (file)
@@ -172,6 +172,9 @@ void sb1250_mailbox_interrupt(void)
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
 
-       if (action & SMP_CALL_FUNCTION)
-               smp_call_function_interrupt();
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
 }
index de30b0c887968c4b985c3c3ab4f9facd082905f0..6edb9ee6128ebc4d45de622afdf118f0bf5d12ee 100644 (file)
@@ -5,6 +5,7 @@ generic-y += cputime.h
 generic-y += exec.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += preempt.h
 generic-y += sections.h
 generic-y += trace_clock.h
diff --git a/arch/mn10300/include/asm/mm-arch-hooks.h b/arch/mn10300/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index e2029a6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_MN10300_MM_ARCH_HOOKS_H
-#define _ASM_MN10300_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_MN10300_MM_ARCH_HOOKS_H */
index 434639d510b3cba669461ca75303eab66782a15d..914864eb5a25daf87688f1565b33700b289be0bf 100644 (file)
@@ -30,6 +30,7 @@ generic-y += kmap_types.h
 generic-y += kvm_para.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
diff --git a/arch/nios2/include/asm/mm-arch-hooks.h b/arch/nios2/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index d7290dc..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_NIOS2_MM_ARCH_HOOKS_H
-#define _ASM_NIOS2_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_NIOS2_MM_ARCH_HOOKS_H */
index e5a693b16da2967ffc112acf0c7561d0e93d5e04..443f44de102093f18fe5d797b297757705a0b70c 100644 (file)
@@ -17,6 +17,7 @@ config OPENRISC
        select GENERIC_IRQ_SHOW
        select GENERIC_IOMAP
        select GENERIC_CPU_DEVICES
+       select HAVE_UID16
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
        select GENERIC_STRNCPY_FROM_USER
@@ -31,9 +32,6 @@ config MMU
 config HAVE_DMA_ATTRS
        def_bool y
 
-config UID16
-       def_bool y
-
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
 
index 2a2e39b8109abd5b503fc4ac3d6ce3e39fd615c9..2832f031fb11d0e86fe695ced404c41cf36ebf90 100644 (file)
@@ -36,6 +36,7 @@ generic-y += kmap_types.h
 generic-y += kvm_para.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
diff --git a/arch/openrisc/include/asm/mm-arch-hooks.h b/arch/openrisc/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 6d33cb5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_OPENRISC_MM_ARCH_HOOKS_H
-#define _ASM_OPENRISC_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_OPENRISC_MM_ARCH_HOOKS_H */
index 12b341d04f88d09be325e318967f537153602d86..f9b3a81aefcdcb5e26cdeaa97026ffdf7622b3f8 100644 (file)
@@ -15,6 +15,7 @@ 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 += mutex.h
 generic-y += param.h
 generic-y += percpu.h
diff --git a/arch/parisc/include/asm/mm-arch-hooks.h b/arch/parisc/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 654ec63..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_PARISC_MM_ARCH_HOOKS_H
-#define _ASM_PARISC_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_PARISC_MM_ARCH_HOOKS_H */
index 3a08eae3318fe8da341a563613ae16e82e64912b..3edbb9fc91b4e055307d3c7519592a00201d988a 100644 (file)
@@ -72,7 +72,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
-       if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
+       if (pmd_flag(*pmd) & PxD_FLAG_ATTACHED) {
                /*
                 * This is the permanent pmd attached to the pgd;
                 * cannot free it.
@@ -81,6 +81,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
                 */
                mm_inc_nr_pmds(mm);
                return;
+       }
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
index 0a183756d6ec2badccc840b881214077edaf556b..f93c4a4e6580300f347a4d69beccc5fe4810452b 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/processor.h>
 #include <asm/cache.h>
 
-extern spinlock_t pa_dbit_lock;
+extern spinlock_t pa_tlb_lock;
 
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
@@ -33,6 +33,19 @@ extern spinlock_t pa_dbit_lock;
  */
 #define kern_addr_valid(addr)  (1)
 
+/* Purge data and instruction TLB entries.  Must be called holding
+ * the pa_tlb_lock.  The TLB purge instructions are slow on SMP
+ * machines since the purge must be broadcast to all CPUs.
+ */
+
+static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+{
+       mtsp(mm->context, 1);
+       pdtlb(addr);
+       if (unlikely(split_tlb))
+               pitlb(addr);
+}
+
 /* Certain architectures need to do special things when PTEs
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
@@ -42,15 +55,20 @@ extern spinlock_t pa_dbit_lock;
                 *(pteptr) = (pteval);                           \
         } while(0)
 
-extern void purge_tlb_entries(struct mm_struct *, unsigned long);
+#define pte_inserted(x)                                                \
+       ((pte_val(x) & (_PAGE_PRESENT|_PAGE_ACCESSED))          \
+        == (_PAGE_PRESENT|_PAGE_ACCESSED))
 
-#define set_pte_at(mm, addr, ptep, pteval)                      \
-       do {                                                    \
+#define set_pte_at(mm, addr, ptep, pteval)                     \
+       do {                                                    \
+               pte_t old_pte;                                  \
                unsigned long flags;                            \
-               spin_lock_irqsave(&pa_dbit_lock, flags);        \
-               set_pte(ptep, pteval);                          \
-               purge_tlb_entries(mm, addr);                    \
-               spin_unlock_irqrestore(&pa_dbit_lock, flags);   \
+               spin_lock_irqsave(&pa_tlb_lock, flags);         \
+               old_pte = *ptep;                                \
+               set_pte(ptep, pteval);                          \
+               if (pte_inserted(old_pte))                      \
+                       purge_tlb_entries(mm, addr);            \
+               spin_unlock_irqrestore(&pa_tlb_lock, flags);    \
        } while (0)
 
 #endif /* !__ASSEMBLY__ */
@@ -268,7 +286,7 @@ extern unsigned long *empty_zero_page;
 
 #define pte_none(x)     (pte_val(x) == 0)
 #define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
-#define pte_clear(mm,addr,xp)  do { pte_val(*(xp)) = 0; } while (0)
+#define pte_clear(mm, addr, xp)  set_pte_at(mm, addr, xp, __pte(0))
 
 #define pmd_flag(x)    (pmd_val(x) & PxD_FLAG_MASK)
 #define pmd_address(x) ((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
@@ -435,15 +453,15 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
        if (!pte_young(*ptep))
                return 0;
 
-       spin_lock_irqsave(&pa_dbit_lock, flags);
+       spin_lock_irqsave(&pa_tlb_lock, flags);
        pte = *ptep;
        if (!pte_young(pte)) {
-               spin_unlock_irqrestore(&pa_dbit_lock, flags);
+               spin_unlock_irqrestore(&pa_tlb_lock, flags);
                return 0;
        }
        set_pte(ptep, pte_mkold(pte));
        purge_tlb_entries(vma->vm_mm, addr);
-       spin_unlock_irqrestore(&pa_dbit_lock, flags);
+       spin_unlock_irqrestore(&pa_tlb_lock, flags);
        return 1;
 }
 
@@ -453,11 +471,12 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        pte_t old_pte;
        unsigned long flags;
 
-       spin_lock_irqsave(&pa_dbit_lock, flags);
+       spin_lock_irqsave(&pa_tlb_lock, flags);
        old_pte = *ptep;
-       pte_clear(mm,addr,ptep);
-       purge_tlb_entries(mm, addr);
-       spin_unlock_irqrestore(&pa_dbit_lock, flags);
+       set_pte(ptep, __pte(0));
+       if (pte_inserted(old_pte))
+               purge_tlb_entries(mm, addr);
+       spin_unlock_irqrestore(&pa_tlb_lock, flags);
 
        return old_pte;
 }
@@ -465,10 +484,10 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        unsigned long flags;
-       spin_lock_irqsave(&pa_dbit_lock, flags);
+       spin_lock_irqsave(&pa_tlb_lock, flags);
        set_pte(ptep, pte_wrprotect(*ptep));
        purge_tlb_entries(mm, addr);
-       spin_unlock_irqrestore(&pa_dbit_lock, flags);
+       spin_unlock_irqrestore(&pa_tlb_lock, flags);
 }
 
 #define pte_same(A,B)  (pte_val(A) == pte_val(B))
index 9d086a599fa05f56a13cbd6b214b466ad4b43a12..e84b96478193ca959c27ec9493d298f845ac6030 100644 (file)
@@ -13,6 +13,9 @@
  * active at any one time on the Merced bus.  This tlb purge
  * synchronisation is fairly lightweight and harmless so we activate
  * it on all systems not just the N class.
+
+ * It is also used to ensure PTE updates are atomic and consistent
+ * with the TLB.
  */
 extern spinlock_t pa_tlb_lock;
 
@@ -24,20 +27,24 @@ extern void flush_tlb_all_local(void *);
 
 #define smp_flush_tlb_all()    flush_tlb_all()
 
+int __flush_tlb_range(unsigned long sid,
+       unsigned long start, unsigned long end);
+
+#define flush_tlb_range(vma, start, end) \
+       __flush_tlb_range((vma)->vm_mm->context, start, end)
+
+#define flush_tlb_kernel_range(start, end) \
+       __flush_tlb_range(0, start, end)
+
 /*
  * flush_tlb_mm()
  *
- * XXX This code is NOT valid for HP-UX compatibility processes,
- * (although it will probably work 99% of the time). HP-UX
- * processes are free to play with the space id's and save them
- * over long periods of time, etc. so we have to preserve the
- * space and just flush the entire tlb. We need to check the
- * personality in order to do that, but the personality is not
- * currently being set correctly.
- *
- * Of course, Linux processes could do the same thing, but
- * we don't support that (and the compilers, dynamic linker,
- * etc. do not do that).
+ * The code to switch to a new context is NOT valid for processes
+ * which play with the space id's.  Thus, we have to preserve the
+ * space and just flush the entire tlb.  However, the compilers,
+ * dynamic linker, etc, do not manipulate space id's, so there
+ * could be a significant performance benefit in switching contexts
+ * and not flushing the whole tlb.
  */
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
@@ -45,10 +52,18 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
        BUG_ON(mm == &init_mm); /* Should never happen */
 
 #if 1 || defined(CONFIG_SMP)
+       /* Except for very small threads, flushing the whole TLB is
+        * faster than using __flush_tlb_range.  The pdtlb and pitlb
+        * instructions are very slow because of the TLB broadcast.
+        * It might be faster to do local range flushes on all CPUs
+        * on PA 2.0 systems.
+        */
        flush_tlb_all();
 #else
        /* FIXME: currently broken, causing space id and protection ids
-        *  to go out of sync, resulting in faults on userspace accesses.
+        * to go out of sync, resulting in faults on userspace accesses.
+        * This approach needs further investigation since running many
+        * small applications (e.g., GCC testsuite) is faster on HP-UX.
         */
        if (mm) {
                if (mm->context != 0)
@@ -65,22 +80,12 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
 {
        unsigned long flags, sid;
 
-       /* For one page, it's not worth testing the split_tlb variable */
-
-       mb();
        sid = vma->vm_mm->context;
        purge_tlb_start(flags);
        mtsp(sid, 1);
        pdtlb(addr);
-       pitlb(addr);
+       if (unlikely(split_tlb))
+               pitlb(addr);
        purge_tlb_end(flags);
 }
-
-void __flush_tlb_range(unsigned long sid,
-       unsigned long start, unsigned long end);
-
-#define flush_tlb_range(vma,start,end) __flush_tlb_range((vma)->vm_mm->context,start,end)
-
-#define flush_tlb_kernel_range(start, end) __flush_tlb_range(0,start,end)
-
 #endif
index f6448c7c62b51f3785c758b2073b0eb967362633..cda6dbbe98426c4bd77a7c0ff31f0525b06fc2ee 100644 (file)
@@ -342,12 +342,15 @@ EXPORT_SYMBOL(flush_data_cache_local);
 EXPORT_SYMBOL(flush_kernel_icache_range_asm);
 
 #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
-int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
+static unsigned long parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
+
+#define FLUSH_TLB_THRESHOLD (2*1024*1024) /* 2MB initial TLB threshold */
+static unsigned long parisc_tlb_flush_threshold __read_mostly = FLUSH_TLB_THRESHOLD;
 
 void __init parisc_setup_cache_timing(void)
 {
        unsigned long rangetime, alltime;
-       unsigned long size;
+       unsigned long size, start;
 
        alltime = mfctl(16);
        flush_data_cache();
@@ -364,14 +367,43 @@ void __init parisc_setup_cache_timing(void)
        /* Racy, but if we see an intermediate value, it's ok too... */
        parisc_cache_flush_threshold = size * alltime / rangetime;
 
-       parisc_cache_flush_threshold = (parisc_cache_flush_threshold + L1_CACHE_BYTES - 1) &~ (L1_CACHE_BYTES - 1); 
+       parisc_cache_flush_threshold = L1_CACHE_ALIGN(parisc_cache_flush_threshold);
        if (!parisc_cache_flush_threshold)
                parisc_cache_flush_threshold = FLUSH_THRESHOLD;
 
        if (parisc_cache_flush_threshold > cache_info.dc_size)
                parisc_cache_flush_threshold = cache_info.dc_size;
 
-       printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
+       printk(KERN_INFO "Setting cache flush threshold to %lu kB\n",
+               parisc_cache_flush_threshold/1024);
+
+       /* calculate TLB flush threshold */
+
+       alltime = mfctl(16);
+       flush_tlb_all();
+       alltime = mfctl(16) - alltime;
+
+       size = PAGE_SIZE;
+       start = (unsigned long) _text;
+       rangetime = mfctl(16);
+       while (start < (unsigned long) _end) {
+               flush_tlb_kernel_range(start, start + PAGE_SIZE);
+               start += PAGE_SIZE;
+               size += PAGE_SIZE;
+       }
+       rangetime = mfctl(16) - rangetime;
+
+       printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n",
+               alltime, size, rangetime);
+
+       parisc_tlb_flush_threshold = size * alltime / rangetime;
+       parisc_tlb_flush_threshold *= num_online_cpus();
+       parisc_tlb_flush_threshold = PAGE_ALIGN(parisc_tlb_flush_threshold);
+       if (!parisc_tlb_flush_threshold)
+               parisc_tlb_flush_threshold = FLUSH_TLB_THRESHOLD;
+
+       printk(KERN_INFO "Setting TLB flush threshold to %lu kB\n",
+               parisc_tlb_flush_threshold/1024);
 }
 
 extern void purge_kernel_dcache_page_asm(unsigned long);
@@ -403,48 +435,45 @@ void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
 }
 EXPORT_SYMBOL(copy_user_page);
 
-void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
-{
-       unsigned long flags;
-
-       /* Note: purge_tlb_entries can be called at startup with
-          no context.  */
-
-       purge_tlb_start(flags);
-       mtsp(mm->context, 1);
-       pdtlb(addr);
-       pitlb(addr);
-       purge_tlb_end(flags);
-}
-EXPORT_SYMBOL(purge_tlb_entries);
-
-void __flush_tlb_range(unsigned long sid, unsigned long start,
-                      unsigned long end)
+/* __flush_tlb_range()
+ *
+ * returns 1 if all TLBs were flushed.
+ */
+int __flush_tlb_range(unsigned long sid, unsigned long start,
+                     unsigned long end)
 {
-       unsigned long npages;
+       unsigned long flags, size;
 
-       npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
-       if (npages >= 512)  /* 2MB of space: arbitrary, should be tuned */
+       size = (end - start);
+       if (size >= parisc_tlb_flush_threshold) {
                flush_tlb_all();
-       else {
-               unsigned long flags;
+               return 1;
+       }
 
+       /* Purge TLB entries for small ranges using the pdtlb and
+          pitlb instructions.  These instructions execute locally
+          but cause a purge request to be broadcast to other TLBs.  */
+       if (likely(!split_tlb)) {
+               while (start < end) {
+                       purge_tlb_start(flags);
+                       mtsp(sid, 1);
+                       pdtlb(start);
+                       purge_tlb_end(flags);
+                       start += PAGE_SIZE;
+               }
+               return 0;
+       }
+
+       /* split TLB case */
+       while (start < end) {
                purge_tlb_start(flags);
                mtsp(sid, 1);
-               if (split_tlb) {
-                       while (npages--) {
-                               pdtlb(start);
-                               pitlb(start);
-                               start += PAGE_SIZE;
-                       }
-               } else {
-                       while (npages--) {
-                               pdtlb(start);
-                               start += PAGE_SIZE;
-                       }
-               }
+               pdtlb(start);
+               pitlb(start);
                purge_tlb_end(flags);
+               start += PAGE_SIZE;
        }
+       return 0;
 }
 
 static void cacheflush_h_tmp_function(void *dummy)
index 75819617f93b9c8fe3e7cd1c655354c83e338360..c5ef4081b01d2f0aee841a7f8f06b0be416a6fd8 100644 (file)
@@ -45,7 +45,7 @@
        .level 2.0
 #endif
 
-       .import         pa_dbit_lock,data
+       .import         pa_tlb_lock,data
 
        /* space_to_prot macro creates a prot id from a space id */
 
        SHLREG          %r9,PxD_VALUE_SHIFT,\pmd
        extru           \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
        dep             %r0,31,PAGE_SHIFT,\pmd  /* clear offset */
-       shladd          \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
-       LDREG           %r0(\pmd),\pte          /* pmd is now pte */
+       shladd          \index,BITS_PER_PTE_ENTRY,\pmd,\pmd /* pmd is now pte */
+       LDREG           %r0(\pmd),\pte
        bb,>=,n         \pte,_PAGE_PRESENT_BIT,\fault
        .endm
 
        L2_ptep         \pgd,\pte,\index,\va,\fault
        .endm
 
-       /* Acquire pa_dbit_lock lock. */
-       .macro          dbit_lock       spc,tmp,tmp1
+       /* Acquire pa_tlb_lock lock and recheck page is still present. */
+       .macro          tlb_lock        spc,ptp,pte,tmp,tmp1,fault
 #ifdef CONFIG_SMP
        cmpib,COND(=),n 0,\spc,2f
-       load32          PA(pa_dbit_lock),\tmp
+       load32          PA(pa_tlb_lock),\tmp
 1:     LDCW            0(\tmp),\tmp1
        cmpib,COND(=)   0,\tmp1,1b
        nop
+       LDREG           0(\ptp),\pte
+       bb,<,n          \pte,_PAGE_PRESENT_BIT,2f
+       b               \fault
+       stw              \spc,0(\tmp)
 2:
 #endif
        .endm
 
-       /* Release pa_dbit_lock lock without reloading lock address. */
-       .macro          dbit_unlock0    spc,tmp
+       /* Release pa_tlb_lock lock without reloading lock address. */
+       .macro          tlb_unlock0     spc,tmp
 #ifdef CONFIG_SMP
        or,COND(=)      %r0,\spc,%r0
        stw             \spc,0(\tmp)
 #endif
        .endm
 
-       /* Release pa_dbit_lock lock. */
-       .macro          dbit_unlock1    spc,tmp
+       /* Release pa_tlb_lock lock. */
+       .macro          tlb_unlock1     spc,tmp
 #ifdef CONFIG_SMP
-       load32          PA(pa_dbit_lock),\tmp
-       dbit_unlock0    \spc,\tmp
+       load32          PA(pa_tlb_lock),\tmp
+       tlb_unlock0     \spc,\tmp
 #endif
        .endm
 
        /* Set the _PAGE_ACCESSED bit of the PTE.  Be clever and
         * don't needlessly dirty the cache line if it was already set */
-       .macro          update_ptep     spc,ptep,pte,tmp,tmp1
-#ifdef CONFIG_SMP
-       or,COND(=)      %r0,\spc,%r0
-       LDREG           0(\ptep),\pte
-#endif
+       .macro          update_accessed ptp,pte,tmp,tmp1
        ldi             _PAGE_ACCESSED,\tmp1
        or              \tmp1,\pte,\tmp
        and,COND(<>)    \tmp1,\pte,%r0
-       STREG           \tmp,0(\ptep)
+       STREG           \tmp,0(\ptp)
        .endm
 
        /* Set the dirty bit (and accessed bit).  No need to be
         * clever, this is only used from the dirty fault */
-       .macro          update_dirty    spc,ptep,pte,tmp
-#ifdef CONFIG_SMP
-       or,COND(=)      %r0,\spc,%r0
-       LDREG           0(\ptep),\pte
-#endif
+       .macro          update_dirty    ptp,pte,tmp
        ldi             _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
        or              \tmp,\pte,\pte
-       STREG           \pte,0(\ptep)
+       STREG           \pte,0(\ptp)
        .endm
 
        /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
@@ -1148,14 +1144,14 @@ dtlb_miss_20w:
 
        L3_ptep         ptp,pte,t0,va,dtlb_check_alias_20w
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,dtlb_check_alias_20w
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
        
        idtlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1174,14 +1170,14 @@ nadtlb_miss_20w:
 
        L3_ptep         ptp,pte,t0,va,nadtlb_check_alias_20w
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,nadtlb_check_alias_20w
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
 
        idtlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1202,20 +1198,20 @@ dtlb_miss_11:
 
        L2_ptep         ptp,pte,t0,va,dtlb_check_alias_11
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,dtlb_check_alias_11
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb_11      spc,pte,prot
 
-       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
 
        idtlba          pte,(%sr1,va)
        idtlbp          prot,(%sr1,va)
 
-       mtsp            t0, %sr1        /* Restore sr1 */
-       dbit_unlock1    spc,t0
+       mtsp            t1, %sr1        /* Restore sr1 */
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1235,21 +1231,20 @@ nadtlb_miss_11:
 
        L2_ptep         ptp,pte,t0,va,nadtlb_check_alias_11
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,nadtlb_check_alias_11
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb_11      spc,pte,prot
 
-
-       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
 
        idtlba          pte,(%sr1,va)
        idtlbp          prot,(%sr1,va)
 
-       mtsp            t0, %sr1        /* Restore sr1 */
-       dbit_unlock1    spc,t0
+       mtsp            t1, %sr1        /* Restore sr1 */
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1269,16 +1264,16 @@ dtlb_miss_20:
 
        L2_ptep         ptp,pte,t0,va,dtlb_check_alias_20
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,dtlb_check_alias_20
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
 
-       f_extend        pte,t0
+       f_extend        pte,t1
 
        idtlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1297,16 +1292,16 @@ nadtlb_miss_20:
 
        L2_ptep         ptp,pte,t0,va,nadtlb_check_alias_20
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,nadtlb_check_alias_20
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
 
-       f_extend        pte,t0
+       f_extend        pte,t1
        
-        idtlbt          pte,prot
-       dbit_unlock1    spc,t0
+       idtlbt          pte,prot
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1406,14 +1401,14 @@ itlb_miss_20w:
 
        L3_ptep         ptp,pte,t0,va,itlb_fault
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,itlb_fault
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
        
        iitlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1430,14 +1425,14 @@ naitlb_miss_20w:
 
        L3_ptep         ptp,pte,t0,va,naitlb_check_alias_20w
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,naitlb_check_alias_20w
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
 
        iitlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1458,20 +1453,20 @@ itlb_miss_11:
 
        L2_ptep         ptp,pte,t0,va,itlb_fault
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,itlb_fault
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb_11      spc,pte,prot
 
-       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
 
        iitlba          pte,(%sr1,va)
        iitlbp          prot,(%sr1,va)
 
-       mtsp            t0, %sr1        /* Restore sr1 */
-       dbit_unlock1    spc,t0
+       mtsp            t1, %sr1        /* Restore sr1 */
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1482,20 +1477,20 @@ naitlb_miss_11:
 
        L2_ptep         ptp,pte,t0,va,naitlb_check_alias_11
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,naitlb_check_alias_11
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb_11      spc,pte,prot
 
-       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
 
        iitlba          pte,(%sr1,va)
        iitlbp          prot,(%sr1,va)
 
-       mtsp            t0, %sr1        /* Restore sr1 */
-       dbit_unlock1    spc,t0
+       mtsp            t1, %sr1        /* Restore sr1 */
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1516,16 +1511,16 @@ itlb_miss_20:
 
        L2_ptep         ptp,pte,t0,va,itlb_fault
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,itlb_fault
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
 
-       f_extend        pte,t0  
+       f_extend        pte,t1
 
        iitlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1536,16 +1531,16 @@ naitlb_miss_20:
 
        L2_ptep         ptp,pte,t0,va,naitlb_check_alias_20
 
-       dbit_lock       spc,t0,t1
-       update_ptep     spc,ptp,pte,t0,t1
+       tlb_lock        spc,ptp,pte,t0,t1,naitlb_check_alias_20
+       update_accessed ptp,pte,t0,t1
 
        make_insert_tlb spc,pte,prot
 
-       f_extend        pte,t0
+       f_extend        pte,t1
 
        iitlbt          pte,prot
-       dbit_unlock1    spc,t0
 
+       tlb_unlock1     spc,t0
        rfir
        nop
 
@@ -1568,14 +1563,14 @@ dbit_trap_20w:
 
        L3_ptep         ptp,pte,t0,va,dbit_fault
 
-       dbit_lock       spc,t0,t1
-       update_dirty    spc,ptp,pte,t1
+       tlb_lock        spc,ptp,pte,t0,t1,dbit_fault
+       update_dirty    ptp,pte,t1
 
        make_insert_tlb spc,pte,prot
                
        idtlbt          pte,prot
-       dbit_unlock0    spc,t0
 
+       tlb_unlock0     spc,t0
        rfir
        nop
 #else
@@ -1588,8 +1583,8 @@ dbit_trap_11:
 
        L2_ptep         ptp,pte,t0,va,dbit_fault
 
-       dbit_lock       spc,t0,t1
-       update_dirty    spc,ptp,pte,t1
+       tlb_lock        spc,ptp,pte,t0,t1,dbit_fault
+       update_dirty    ptp,pte,t1
 
        make_insert_tlb_11      spc,pte,prot
 
@@ -1600,8 +1595,8 @@ dbit_trap_11:
        idtlbp          prot,(%sr1,va)
 
        mtsp            t1, %sr1     /* Restore sr1 */
-       dbit_unlock0    spc,t0
 
+       tlb_unlock0     spc,t0
        rfir
        nop
 
@@ -1612,16 +1607,16 @@ dbit_trap_20:
 
        L2_ptep         ptp,pte,t0,va,dbit_fault
 
-       dbit_lock       spc,t0,t1
-       update_dirty    spc,ptp,pte,t1
+       tlb_lock        spc,ptp,pte,t0,t1,dbit_fault
+       update_dirty    ptp,pte,t1
 
        make_insert_tlb spc,pte,prot
 
        f_extend        pte,t1
        
-        idtlbt          pte,prot
-       dbit_unlock0    spc,t0
+       idtlbt          pte,prot
 
+       tlb_unlock0     spc,t0
        rfir
        nop
 #endif
index 6548fd1d2e62defc2dfc6e8dfc125a42aa8e986e..b99b39f1da02431865b94e6bfe720e9858163a0d 100644 (file)
 
 #include "../math-emu/math-emu.h"      /* for handle_fpe() */
 
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
-DEFINE_SPINLOCK(pa_dbit_lock);
-#endif
-
 static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
        struct pt_regs *regs);
 
index d0ece257d310527743007a60f01f60cc5f684754..04c7e8fc24c207c7909eecfceac2d8e0cbd2722e 100644 (file)
 
 /* Structure of the hardware registers */
 struct mpc52xx_psc {
-       u8              mode;           /* PSC + 0x00 */
+       union {
+               u8      mode;           /* PSC + 0x00 */
+               u8      mr2;
+       };
        u8              reserved0[3];
        union {                         /* PSC + 0x04 */
                u16     status;
index ccde8f084ce426ab382964ec5e2eba389317be44..112ccf4975620f899a4747c98a13cd09260b5598 100644 (file)
 
        .text
 
+/*
+ * Used by threads when the lock bit of core_idle_state is set.
+ * Threads will spin in HMT_LOW until the lock bit is cleared.
+ * r14 - pointer to core_idle_state
+ * r15 - used to load contents of core_idle_state
+ */
+
+core_idle_lock_held:
+       HMT_LOW
+3:     lwz     r15,0(r14)
+       andi.   r15,r15,PNV_CORE_IDLE_LOCK_BIT
+       bne     3b
+       HMT_MEDIUM
+       lwarx   r15,0,r14
+       blr
+
 /*
  * Pass requested state in r3:
  *     r3 - PNV_THREAD_NAP/SLEEP/WINKLE
@@ -150,6 +166,10 @@ power7_enter_nap_mode:
        ld      r14,PACA_CORE_IDLE_STATE_PTR(r13)
 lwarx_loop1:
        lwarx   r15,0,r14
+
+       andi.   r9,r15,PNV_CORE_IDLE_LOCK_BIT
+       bnel    core_idle_lock_held
+
        andc    r15,r15,r7                      /* Clear thread bit */
 
        andi.   r15,r15,PNV_CORE_IDLE_THREAD_BITS
@@ -294,7 +314,7 @@ lwarx_loop2:
         * workaround undo code or resyncing timebase or restoring context
         * In either case loop until the lock bit is cleared.
         */
-       bne     core_idle_lock_held
+       bnel    core_idle_lock_held
 
        cmpwi   cr2,r15,0
        lbz     r4,PACA_SUBCORE_SIBLING_MASK(r13)
@@ -319,15 +339,6 @@ lwarx_loop2:
        isync
        b       common_exit
 
-core_idle_lock_held:
-       HMT_LOW
-core_idle_lock_loop:
-       lwz     r15,0(14)
-       andi.   r9,r15,PNV_CORE_IDLE_LOCK_BIT
-       bne     core_idle_lock_loop
-       HMT_MEDIUM
-       b       lwarx_loop2
-
 first_thread_in_subcore:
        /* First thread in subcore to wakeup */
        ori     r15,r15,PNV_CORE_IDLE_LOCK_BIT
index d3a831ac0f927e17304d55c406c60029ad55a4e0..da50e0c9c57e69af8779f0df979231104704ab6e 100644 (file)
@@ -966,8 +966,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)
 
 int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
 {
-       memset(to, 0, sizeof *to);
-
        if (copy_from_user(to, from, 3*sizeof(int)) ||
            copy_from_user(to->_sifields._pad,
                           from->_sifields._pad, SI_PAD_SIZE32))
index 6530f1b8874dac16dc7f71480b5d748d0ccc268d..37de90f8a845c9ef8f1410100a0d7d3b05b93195 100644 (file)
@@ -297,6 +297,8 @@ long machine_check_early(struct pt_regs *regs)
 
        __this_cpu_inc(irq_stat.mce_exceptions);
 
+       add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
+
        if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
                handled = cur_cpu_spec->machine_check_early(regs);
        return handled;
index 6d535973b200dde0f64ae19a3d47f1eaca6a4c99..a67c6d781c52b9a28ac90b0c6cc1650519e9260c 100644 (file)
@@ -529,6 +529,10 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
                printk(KERN_ALERT "Unable to handle kernel paging request for "
                        "instruction fetch\n");
                break;
+       case 0x600:
+               printk(KERN_ALERT "Unable to handle kernel paging request for "
+                       "unaligned access at address 0x%08lx\n", regs->dar);
+               break;
        default:
                printk(KERN_ALERT "Unable to handle kernel paging request for "
                        "unknown fault\n");
index ec2eb20631d14f12bb6ffa310370a5eb230a9408..df956295c2a7ab3ede23e2a06e650d39943a1b17 100644 (file)
@@ -320,6 +320,8 @@ static struct attribute *device_str_attr_create_(char *name, char *str)
        if (!attr)
                return NULL;
 
+       sysfs_attr_init(&attr->attr.attr);
+
        attr->var = str;
        attr->attr.attr.name = name;
        attr->attr.attr.mode = 0444;
index 5cf5e6ea213baaeee1b6e017636eae95aba6b0c6..7cf0df859d0536bcfd4752d4b581da810873196b 100644 (file)
@@ -1478,7 +1478,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
        }
 
        /* Unmask the event */
-       if (eeh_enabled())
+       if (ret == EEH_NEXT_ERR_NONE && eeh_enabled())
                enable_irq(eeh_event_irq);
 
        return ret;
index 4949ef0d94004e0f315f90e37cc2a50ce3582584..37f959bf392e72a8a4bc7dee92181846b1383458 100644 (file)
@@ -237,7 +237,7 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
        return elog;
 }
 
-static void elog_work_fn(struct work_struct *work)
+static irqreturn_t elog_event(int irq, void *data)
 {
        __be64 size;
        __be64 id;
@@ -251,7 +251,7 @@ static void elog_work_fn(struct work_struct *work)
        rc = opal_get_elog_size(&id, &size, &type);
        if (rc != OPAL_SUCCESS) {
                pr_err("ELOG: OPAL log info read failed\n");
-               return;
+               return IRQ_HANDLED;
        }
 
        elog_size = be64_to_cpu(size);
@@ -270,16 +270,10 @@ static void elog_work_fn(struct work_struct *work)
         * entries.
         */
        if (kset_find_obj(elog_kset, name))
-               return;
+               return IRQ_HANDLED;
 
        create_elog_obj(log_id, elog_size, elog_type);
-}
-
-static DECLARE_WORK(elog_work, elog_work_fn);
 
-static irqreturn_t elog_event(int irq, void *data)
-{
-       schedule_work(&elog_work);
        return IRQ_HANDLED;
 }
 
@@ -304,8 +298,8 @@ int __init opal_elog_init(void)
                return irq;
        }
 
-       rc = request_irq(irq, elog_event,
-                       IRQ_TYPE_LEVEL_HIGH, "opal-elog", NULL);
+       rc = request_threaded_irq(irq, NULL, elog_event,
+                       IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "opal-elog", NULL);
        if (rc) {
                pr_err("%s: Can't request OPAL event irq (%d)\n",
                       __func__, rc);
index 46cb3feb0a13a280a3949f5378e771928c828b63..4ece8e40dd5414868ef9934d7a809578c37f2743 100644 (file)
@@ -112,6 +112,7 @@ static int opal_prd_open(struct inode *inode, struct file *file)
 static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma)
 {
        size_t addr, size;
+       pgprot_t page_prot;
        int rc;
 
        pr_devel("opal_prd_mmap(0x%016lx, 0x%016lx, 0x%lx, 0x%lx)\n",
@@ -125,13 +126,11 @@ static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma)
        if (!opal_prd_range_is_valid(addr, size))
                return -EINVAL;
 
-       vma->vm_page_prot = __pgprot(pgprot_val(phys_mem_access_prot(file,
-                                               vma->vm_pgoff,
-                                                size, vma->vm_page_prot))
-                                       | _PAGE_SPECIAL);
+       page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
+                                        size, vma->vm_page_prot);
 
        rc = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size,
-                       vma->vm_page_prot);
+                               page_prot);
 
        return rc;
 }
index 5738d315248b202b4a26aff084b07e819a80855c..85cbc96eff6cbd60e3e6bb9bf126091181eb5ef1 100644 (file)
@@ -2220,7 +2220,7 @@ static void pnv_pci_ioda_setup_opal_tce_kill(struct pnv_phb *phb)
 
 static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
                unsigned levels, unsigned long limit,
-               unsigned long *current_offset)
+               unsigned long *current_offset, unsigned long *total_allocated)
 {
        struct page *tce_mem = NULL;
        __be64 *addr, *tmp;
@@ -2236,6 +2236,7 @@ static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
        }
        addr = page_address(tce_mem);
        memset(addr, 0, allocated);
+       *total_allocated += allocated;
 
        --levels;
        if (!levels) {
@@ -2245,7 +2246,7 @@ static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
 
        for (i = 0; i < entries; ++i) {
                tmp = pnv_pci_ioda2_table_do_alloc_pages(nid, shift,
-                               levels, limit, current_offset);
+                               levels, limit, current_offset, total_allocated);
                if (!tmp)
                        break;
 
@@ -2267,7 +2268,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
                struct iommu_table *tbl)
 {
        void *addr;
-       unsigned long offset = 0, level_shift;
+       unsigned long offset = 0, level_shift, total_allocated = 0;
        const unsigned window_shift = ilog2(window_size);
        unsigned entries_shift = window_shift - page_shift;
        unsigned table_shift = max_t(unsigned, entries_shift + 3, PAGE_SHIFT);
@@ -2286,7 +2287,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
 
        /* Allocate TCE table */
        addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
-                       levels, tce_table_size, &offset);
+                       levels, tce_table_size, &offset, &total_allocated);
 
        /* addr==NULL means that the first level allocation failed */
        if (!addr)
@@ -2308,7 +2309,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
                        page_shift);
        tbl->it_level_size = 1ULL << (level_shift - 3);
        tbl->it_indirect_levels = levels - 1;
-       tbl->it_allocated_size = offset;
+       tbl->it_allocated_size = total_allocated;
 
        pr_devel("Created TCE table: ws=%08llx ts=%lx @%08llx\n",
                        window_size, tce_table_size, bus_offset);
index 2bc33674ebfc11d2525700191552389fafc1a23d..87f9623ca805d6ba601919784df3c7e6d38e488f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pci.h>
 #include <linux/semaphore.h>
 #include <asm/msi_bitmap.h>
+#include <asm/ppc-pci.h>
 
 struct ppc4xx_hsta_msi {
        struct device *dev;
index dc5385ebb071ac79c08b50c7a4c85b2b0e66f32a..5ad26dd94d77e83fedeba5c7f71c8eba0ff2ab29 100644 (file)
@@ -3,5 +3,6 @@
 generic-y += clkdev.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += preempt.h
 generic-y += trace_clock.h
index cfad7fca01d61d72942d98a37d18e5e0675980bc..d7697ab802f6c94813a27394baa255fa26a93ddc 100644 (file)
@@ -57,7 +57,10 @@ union ctlreg0 {
                unsigned long lap  : 1; /* Low-address-protection control */
                unsigned long      : 4;
                unsigned long edat : 1; /* Enhanced-DAT-enablement control */
-               unsigned long      : 23;
+               unsigned long      : 4;
+               unsigned long afp  : 1; /* AFP-register control */
+               unsigned long vx   : 1; /* Vector enablement control */
+               unsigned long      : 17;
        };
 };
 
index 0130d0379edd179e8b06dbd459066b8606517676..d9be7c0c1291445cfb2356d88b973398fea67b97 100644 (file)
@@ -14,6 +14,7 @@
 
 #define is_hugepage_only_range(mm, addr, len)  0
 #define hugetlb_free_pgd_range                 free_pgd_range
+#define hugepages_supported()                  (MACHINE_HAS_HPAGE)
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, pte_t pte);
diff --git a/arch/s390/include/asm/mm-arch-hooks.h b/arch/s390/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 07680b2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_S390_MM_ARCH_HOOKS_H
-#define _ASM_S390_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_S390_MM_ARCH_HOOKS_H */
index dd345238d9a7762becd9276602122d00b9e87ea5..53eacbd4f09bf4c32ac051f1be7f9d3e5445e0df 100644 (file)
 #define PAGE_DEFAULT_ACC       0
 #define PAGE_DEFAULT_KEY       (PAGE_DEFAULT_ACC << 4)
 
-#include <asm/setup.h>
-#ifndef __ASSEMBLY__
-
-extern int HPAGE_SHIFT;
+#define HPAGE_SHIFT    20
 #define HPAGE_SIZE     (1UL << HPAGE_SHIFT)
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
@@ -30,6 +27,9 @@ extern int HPAGE_SHIFT;
 #define ARCH_HAS_PREPARE_HUGEPAGE
 #define ARCH_HAS_HUGEPAGE_CLEAR_FLUSH
 
+#include <asm/setup.h>
+#ifndef __ASSEMBLY__
+
 static inline void storage_key_init_range(unsigned long start, unsigned long end)
 {
 #if PAGE_DEFAULT_KEY
index 4cb19fe76dd98b13abfc02c9520e37460475e645..f897ec73dc8c9c02943a5c76254140bc951a6024 100644 (file)
@@ -87,7 +87,15 @@ struct sf_raw_sample {
 } __packed;
 
 /* Perf hardware reserve and release functions */
+#ifdef CONFIG_PERF_EVENTS
 int perf_reserve_sampling(void);
 void perf_release_sampling(void);
+#else /* CONFIG_PERF_EVENTS */
+static inline int perf_reserve_sampling(void)
+{
+       return 0;
+}
+static inline void perf_release_sampling(void) {}
+#endif /* CONFIG_PERF_EVENTS */
 
 #endif /* _ASM_S390_PERF_EVENT_H */
index c7d1b9d0901147ba359fa03e2e4e026699413fa2..a2da259d932741614c4f6b78642c491b3829b223 100644 (file)
 
 int main(void)
 {
-       DEFINE(__THREAD_info, offsetof(struct task_struct, stack));
-       DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp));
-       DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment));
-       BLANK();
+       DEFINE(__TASK_thread_info, offsetof(struct task_struct, stack));
+       DEFINE(__TASK_thread, offsetof(struct task_struct, thread));
        DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
        BLANK();
-       DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause));
-       DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));
-       DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));
+       DEFINE(__THREAD_ksp, offsetof(struct thread_struct, ksp));
+       DEFINE(__THREAD_per_cause, offsetof(struct thread_struct, per_event.cause));
+       DEFINE(__THREAD_per_address, offsetof(struct thread_struct, per_event.address));
+       DEFINE(__THREAD_per_paid, offsetof(struct thread_struct, per_event.paid));
+       DEFINE(__THREAD_trap_tdb, offsetof(struct thread_struct, trap_tdb));
        BLANK();
        DEFINE(__TI_task, offsetof(struct thread_info, task));
        DEFINE(__TI_flags, offsetof(struct thread_info, flags));
@@ -176,7 +176,6 @@ int main(void)
        DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data));
        DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap));
        DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
-       DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
        DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
        DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
        DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
index bff5e3b6d8223b8f9a9c84d8f99235d3d4e648bc..8ba32436effe4b9da0a271ae1ec0ad2a2bd689e7 100644 (file)
@@ -138,6 +138,8 @@ int init_cache_level(unsigned int cpu)
        union cache_topology ct;
        enum cache_type ctype;
 
+       if (!test_facility(34))
+               return -EOPNOTSUPP;
        if (!this_cpu_ci)
                return -EINVAL;
        ct.raw = ecag(EXTRACT_TOPOLOGY, 0, 0);
index 3238893c9d4ff66d492ce2a04421b85fa0cc0c34..84062e7a77dad75c50fa60822255ee2b20b34181 100644 (file)
@@ -178,17 +178,21 @@ _PIF_WORK = (_PIF_PER_TRAP)
  */
 ENTRY(__switch_to)
        stmg    %r6,%r15,__SF_GPRS(%r15)        # store gprs of prev task
-       stg     %r15,__THREAD_ksp(%r2)          # store kernel stack of prev
-       lg      %r4,__THREAD_info(%r2)          # get thread_info of prev
-       lg      %r5,__THREAD_info(%r3)          # get thread_info of next
+       lgr     %r1,%r2
+       aghi    %r1,__TASK_thread               # thread_struct of prev task
+       lg      %r4,__TASK_thread_info(%r2)     # get thread_info of prev
+       lg      %r5,__TASK_thread_info(%r3)     # get thread_info of next
+       stg     %r15,__THREAD_ksp(%r1)          # store kernel stack of prev
+       lgr     %r1,%r3
+       aghi    %r1,__TASK_thread               # thread_struct of next task
        lgr     %r15,%r5
        aghi    %r15,STACK_INIT                 # end of kernel stack of next
        stg     %r3,__LC_CURRENT                # store task struct of next
        stg     %r5,__LC_THREAD_INFO            # store thread info of next
        stg     %r15,__LC_KERNEL_STACK          # store end of kernel stack
+       lg      %r15,__THREAD_ksp(%r1)          # load kernel stack of next
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        mvc     __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
-       lg      %r15,__THREAD_ksp(%r3)          # load kernel stack of next
        lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        br      %r14
 
@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler)
        LAST_BREAK %r14
        lg      %r15,__LC_KERNEL_STACK
        lg      %r14,__TI_task(%r12)
+       aghi    %r14,__TASK_thread      # pointer to thread_struct
        lghi    %r13,__LC_PGM_TDB
        tm      __LC_PGM_ILC+2,0x02     # check for transaction abort
        jz      2f
index 505c17c0ae1a67a93542c963ce800f7e8d9a11db..56b550893593a58a5ab07879a2fa3561cde009d4 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/nmi.h>
 #include <asm/crw.h>
 #include <asm/switch_to.h>
+#include <asm/ctl_reg.h>
 
 struct mcck_struct {
        int kill_task;
@@ -129,26 +130,30 @@ static int notrace s390_revalidate_registers(struct mci *mci)
        } else
                asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
 
-       asm volatile(
-               "       ld      0,0(%0)\n"
-               "       ld      1,8(%0)\n"
-               "       ld      2,16(%0)\n"
-               "       ld      3,24(%0)\n"
-               "       ld      4,32(%0)\n"
-               "       ld      5,40(%0)\n"
-               "       ld      6,48(%0)\n"
-               "       ld      7,56(%0)\n"
-               "       ld      8,64(%0)\n"
-               "       ld      9,72(%0)\n"
-               "       ld      10,80(%0)\n"
-               "       ld      11,88(%0)\n"
-               "       ld      12,96(%0)\n"
-               "       ld      13,104(%0)\n"
-               "       ld      14,112(%0)\n"
-               "       ld      15,120(%0)\n"
-               : : "a" (fpt_save_area));
-       /* Revalidate vector registers */
-       if (MACHINE_HAS_VX && current->thread.vxrs) {
+       if (!MACHINE_HAS_VX) {
+               /* Revalidate floating point registers */
+               asm volatile(
+                       "       ld      0,0(%0)\n"
+                       "       ld      1,8(%0)\n"
+                       "       ld      2,16(%0)\n"
+                       "       ld      3,24(%0)\n"
+                       "       ld      4,32(%0)\n"
+                       "       ld      5,40(%0)\n"
+                       "       ld      6,48(%0)\n"
+                       "       ld      7,56(%0)\n"
+                       "       ld      8,64(%0)\n"
+                       "       ld      9,72(%0)\n"
+                       "       ld      10,80(%0)\n"
+                       "       ld      11,88(%0)\n"
+                       "       ld      12,96(%0)\n"
+                       "       ld      13,104(%0)\n"
+                       "       ld      14,112(%0)\n"
+                       "       ld      15,120(%0)\n"
+                       : : "a" (fpt_save_area));
+       } else {
+               /* Revalidate vector registers */
+               union ctlreg0 cr0;
+
                if (!mci->vr) {
                        /*
                         * Vector registers can't be restored and therefore
@@ -156,8 +161,12 @@ static int notrace s390_revalidate_registers(struct mci *mci)
                         */
                        kill_task = 1;
                }
+               cr0.val = S390_lowcore.cregs_save_area[0];
+               cr0.afp = cr0.vx = 1;
+               __ctl_load(cr0.val, 0, 0);
                restore_vx_regs((__vector128 *)
-                               S390_lowcore.vector_save_area_addr);
+                               &S390_lowcore.vector_save_area);
+               __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
        }
        /* Revalidate access registers */
        asm volatile(
index dc5edc29b73aaf120bd462d93fd371c2803daf18..8f587d871b9f234bed189b9c568746930d1045f3 100644 (file)
@@ -163,7 +163,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
 asmlinkage void execve_tail(void)
 {
        current->thread.fp_regs.fpc = 0;
-       asm volatile("sfpc %0,%0" : : "d" (0));
+       asm volatile("sfpc %0" : : "d" (0));
 }
 
 /*
index 43c3169ea49c7d019543d8e2754dd3061fd95789..ada0c07fe1a8744ecf989093720422cac1429e66 100644 (file)
@@ -270,6 +270,8 @@ ENTRY(_sclp_print_early)
        jno     .Lesa2
        ahi     %r15,-80
        stmh    %r6,%r15,96(%r15)               # store upper register halves
+       basr    %r13,0
+       lmh     %r0,%r15,.Lzeroes-.(%r13)       # clear upper register halves
 .Lesa2:
        lr      %r10,%r2                        # save string pointer
        lhi     %r2,0
@@ -291,6 +293,8 @@ ENTRY(_sclp_print_early)
 .Lesa3:
        lm      %r6,%r15,120(%r15)              # restore registers
        br      %r14
+.Lzeroes:
+       .fill   64,4,0
 
 .LwritedataS4:
        .long   0x00760005                      # SCLP command for write data
index f7f027caaaaacb33b279f76b33f3525374b6ae34..ca070d260af2e166b23b48553b2b6c02dc2a1046 100644 (file)
@@ -885,8 +885,6 @@ void __init setup_arch(char **cmdline_p)
         */
        setup_hwcaps();
 
-       HPAGE_SHIFT = MACHINE_HAS_HPAGE ? 20 : 0;
-
        /*
         * Create kernel page tables and switch to virtual addressing.
         */
index 4d96c9f5345538471cea4cd62620439c88a7f867..7bea81d8a3635025b0f372c3f908ade71b188e1b 100644 (file)
@@ -259,7 +259,7 @@ void vector_exception(struct pt_regs *regs)
        }
 
        /* get vector interrupt code from fpc */
-       asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+       asm volatile("stfpc %0" : "=Q" (current->thread.fp_regs.fpc));
        vic = (current->thread.fp_regs.fpc & 0xf00) >> 8;
        switch (vic) {
        case 1: /* invalid vector operation */
@@ -297,7 +297,7 @@ void data_exception(struct pt_regs *regs)
 
        location = get_trap_ip(regs);
 
-       asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+       asm volatile("stfpc %0" : "=Q" (current->thread.fp_regs.fpc));
        /* Check for vector register enablement */
        if (MACHINE_HAS_VX && !current->thread.vxrs &&
            (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) {
index 2078f92d15ac90adcfec617b46df750e073b76d0..f32f843a3631359e49b88169ab8a1eed2b76b946 100644 (file)
@@ -1742,10 +1742,10 @@ static bool ibs_enabled(struct kvm_vcpu *vcpu)
 
 static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->requests)
-               return 0;
 retry:
        kvm_s390_vcpu_request_handled(vcpu);
+       if (!vcpu->requests)
+               return 0;
        /*
         * We use MMU_RELOAD just to re-arm the ipte notifier for the
         * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
index 33082d0d101b59e41690435b7f35896cde14fe0f..b33f66110ca9401418f7d657b951d8bfb84d99c3 100644 (file)
@@ -31,8 +31,6 @@
 #define ALLOC_ORDER    2
 #define FRAG_MASK      0x03
 
-int HPAGE_SHIFT;
-
 unsigned long *crst_table_alloc(struct mm_struct *mm)
 {
        struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
index fee782acc2ee51f6a3aae4b28152ec76981c8350..8d2e5165865f2c27b50fe8b1c6845de45666698a 100644 (file)
@@ -448,13 +448,13 @@ static void bpf_jit_prologue(struct bpf_jit *jit)
                EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0,
                              BPF_REG_1, offsetof(struct sk_buff, data));
        }
-       /* BPF compatibility: clear A (%b7) and X (%b8) registers */
-       if (REG_SEEN(BPF_REG_7))
-               /* lghi %b7,0 */
-               EMIT4_IMM(0xa7090000, BPF_REG_7, 0);
-       if (REG_SEEN(BPF_REG_8))
-               /* lghi %b8,0 */
-               EMIT4_IMM(0xa7090000, BPF_REG_8, 0);
+       /* BPF compatibility: clear A (%b0) and X (%b7) registers */
+       if (REG_SEEN(BPF_REG_A))
+               /* lghi %ba,0 */
+               EMIT4_IMM(0xa7090000, BPF_REG_A, 0);
+       if (REG_SEEN(BPF_REG_X))
+               /* lghi %bx,0 */
+               EMIT4_IMM(0xa7090000, BPF_REG_X, 0);
 }
 
 /*
index bc927a09a172b6d6699cf60610cde600d4c73e74..9cfa2ffaa9d6bb02dd29cb01d895a0feaf63bdb0 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <asm/processor.h>
+#include <asm/perf_event.h>
 
 #include "../../../drivers/oprofile/oprof.h"
 
index 138fb3db45ba66ee03b7471025b4881af80cc874..92ffe397b893c553c8504f10525a5e3d9d1e9e34 100644 (file)
@@ -7,6 +7,7 @@ generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += irq_work.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += preempt.h
 generic-y += sections.h
 generic-y += trace_clock.h
diff --git a/arch/score/include/asm/mm-arch-hooks.h b/arch/score/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 5e38689..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_SCORE_MM_ARCH_HOOKS_H
-#define _ASM_SCORE_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_SCORE_MM_ARCH_HOOKS_H */
index 9ac4626e72844b3fe6e4f659b75ffc01fe375610..aac452b26aa896a00cd59c65977739ed078d9201 100644 (file)
@@ -16,6 +16,7 @@ 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
diff --git a/arch/sh/include/asm/mm-arch-hooks.h b/arch/sh/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 1808729..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_SH_MM_ARCH_HOOKS_H
-#define _ASM_SH_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_SH_MM_ARCH_HOOKS_H */
index 2b2a69dcc467cbdb7e9aa895fe1a98acfb86ce4d..e928618838bc53c83555cc7b275073fc8c745b3d 100644 (file)
@@ -12,6 +12,7 @@ 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 += module.h
 generic-y += mutex.h
 generic-y += preempt.h
diff --git a/arch/sparc/include/asm/mm-arch-hooks.h b/arch/sparc/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index b89ba44..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_SPARC_MM_ARCH_HOOKS_H
-#define _ASM_SPARC_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_SPARC_MM_ARCH_HOOKS_H */
index 1f0aa2024e94be341efc079f58145a2e70909052..6424249d5f785e698c4283677c1b975668393478 100644 (file)
  * Must preserve %o5 between VISEntryHalf and VISExitHalf */
 
 #define VISEntryHalf                                   \
-       rd              %fprs, %o5;                     \
-       andcc           %o5, FPRS_FEF, %g0;             \
-       be,pt           %icc, 297f;                     \
-        sethi          %hi(298f), %g7;                 \
-       sethi           %hi(VISenterhalf), %g1;         \
-       jmpl            %g1 + %lo(VISenterhalf), %g0;   \
-        or             %g7, %lo(298f), %g7;            \
-       clr             %o5;                            \
-297:   wr              %o5, FPRS_FEF, %fprs;           \
-298:
+       VISEntry
+
+#define VISExitHalf                                    \
+       VISExit
 
 #define VISEntryHalfFast(fail_label)                   \
        rd              %fprs, %o5;                     \
@@ -47,7 +41,7 @@
        ba,a,pt         %xcc, fail_label;               \
 297:   wr              %o5, FPRS_FEF, %fprs;
 
-#define VISExitHalf                                    \
+#define VISExitHalfFast                                        \
        wr              %o5, 0, %fprs;
 
 #ifndef __ASSEMBLY__
index 140527a20e7df03cc0a0dd9e6a3438f44b432177..83aeeb1dffdb3b4c29293d5924cd5259e2269ce5 100644 (file)
@@ -240,8 +240,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
        add             %o0, 0x40, %o0
        bne,pt          %icc, 1b
         LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
+#ifdef NON_USER_COPY
+       VISExitHalfFast
+#else
        VISExitHalf
-
+#endif
        brz,pn          %o2, .Lexit
         cmp            %o2, 19
        ble,pn          %icc, .Lsmall_unaligned
index b320ae9e2e2e8b27c7184f58ddc640b4adf6fdda..a063d84336d6384a03d7ddd8a5143f0909801ed8 100644 (file)
@@ -44,9 +44,8 @@ vis1: ldub            [%g6 + TI_FPSAVED], %g3
 
         stx            %g3, [%g6 + TI_GSR]
 2:     add             %g6, %g1, %g3
-       cmp             %o5, FPRS_DU
-       be,pn           %icc, 6f
-        sll            %g1, 3, %g1
+       mov             FPRS_DU | FPRS_DL | FPRS_FEF, %o5
+       sll             %g1, 3, %g1
        stb             %o5, [%g3 + TI_FPSAVED]
        rd              %gsr, %g2
        add             %g6, %g1, %g3
@@ -80,65 +79,3 @@ vis1:        ldub            [%g6 + TI_FPSAVED], %g3
        .align          32
 80:    jmpl            %g7 + %g0, %g0
         nop
-
-6:     ldub            [%g3 + TI_FPSAVED], %o5
-       or              %o5, FPRS_DU, %o5
-       add             %g6, TI_FPREGS+0x80, %g2
-       stb             %o5, [%g3 + TI_FPSAVED]
-
-       sll             %g1, 5, %g1
-       add             %g6, TI_FPREGS+0xc0, %g3
-       wr              %g0, FPRS_FEF, %fprs
-       membar          #Sync
-       stda            %f32, [%g2 + %g1] ASI_BLK_P
-       stda            %f48, [%g3 + %g1] ASI_BLK_P
-       membar          #Sync
-       ba,pt           %xcc, 80f
-        nop
-
-       .align          32
-80:    jmpl            %g7 + %g0, %g0
-        nop
-
-       .align          32
-VISenterhalf:
-       ldub            [%g6 + TI_FPDEPTH], %g1
-       brnz,a,pn       %g1, 1f
-        cmp            %g1, 1
-       stb             %g0, [%g6 + TI_FPSAVED]
-       stx             %fsr, [%g6 + TI_XFSR]
-       clr             %o5
-       jmpl            %g7 + %g0, %g0
-        wr             %g0, FPRS_FEF, %fprs
-
-1:     bne,pn          %icc, 2f
-        srl            %g1, 1, %g1
-       ba,pt           %xcc, vis1
-        sub            %g7, 8, %g7
-2:     addcc           %g6, %g1, %g3
-       sll             %g1, 3, %g1
-       andn            %o5, FPRS_DU, %g2
-       stb             %g2, [%g3 + TI_FPSAVED]
-
-       rd              %gsr, %g2
-       add             %g6, %g1, %g3
-       stx             %g2, [%g3 + TI_GSR]
-       add             %g6, %g1, %g2
-       stx             %fsr, [%g2 + TI_XFSR]
-       sll             %g1, 5, %g1
-3:     andcc           %o5, FPRS_DL, %g0
-       be,pn           %icc, 4f
-        add            %g6, TI_FPREGS, %g2
-
-       add             %g6, TI_FPREGS+0x40, %g3
-       membar          #Sync
-       stda            %f0, [%g2 + %g1] ASI_BLK_P
-       stda            %f16, [%g3 + %g1] ASI_BLK_P
-       membar          #Sync
-       ba,pt           %xcc, 4f
-        nop
-
-       .align          32
-4:     and             %o5, FPRS_DU, %o5
-       jmpl            %g7 + %g0, %g0
-        wr             %o5, FPRS_FEF, %fprs
index 1d649a95660c8cad57fbe90feadb7c43b9e8263f..8069ce12f20b13d514160cec8db0c0d88b64b27e 100644 (file)
@@ -135,10 +135,6 @@ EXPORT_SYMBOL(copy_user_page);
 void VISenter(void);
 EXPORT_SYMBOL(VISenter);
 
-/* CRYPTO code needs this */
-void VISenterhalf(void);
-EXPORT_SYMBOL(VISenterhalf);
-
 extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
 extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
                unsigned long *);
index d53654488c2c1529d0a3aede5836eeb11b3bcde5..d8a84316347127a48a7663ac833ab6d368d9118e 100644 (file)
@@ -19,6 +19,7 @@ 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 += mutex.h
 generic-y += param.h
diff --git a/arch/tile/include/asm/mm-arch-hooks.h b/arch/tile/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index d1709ea..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_TILE_MM_ARCH_HOOKS_H
-#define _ASM_TILE_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_TILE_MM_ARCH_HOOKS_H */
index e8c2c04143cda81db9b51018a449b611263ab68d..c667e104a0c251d73f02ce2b812ed09878ca79a0 100644 (file)
@@ -113,8 +113,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
        if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
                return -EFAULT;
 
-       memset(to, 0, sizeof(*to));
-
        err = __get_user(to->si_signo, &from->si_signo);
        err |= __get_user(to->si_errno, &from->si_errno);
        err |= __get_user(to->si_code, &from->si_code);
index 99c9ff87e0187502179f8012afa5bd54309d2eb9..6b755d125783f45b05de02e3fe5f7b5e32d1af45 100644 (file)
@@ -1139,7 +1139,7 @@ static void __init load_hv_initrd(void)
 
 void __init free_initrd_mem(unsigned long begin, unsigned long end)
 {
-       free_bootmem(__pa(begin), end - begin);
+       free_bootmem_late(__pa(begin), end - begin);
 }
 
 static int __init setup_initrd(char *str)
index 88c7016492c4dcbcddbc11e5851e86d9fe2608aa..97bbb6060b2526127565541b57b170a5a70bbc10 100644 (file)
@@ -28,7 +28,7 @@
 #define _ST(p, inst, v)                                                \
        ({                                                      \
                asm("1: " #inst " %0, %1;"                      \
-                   ".pushsection .coldtext.memcpy,\"ax\";"     \
+                   ".pushsection .coldtext,\"ax\";"    \
                    "2: { move r0, %2; jrp lr };"               \
                    ".section __ex_table,\"a\";"                \
                    ".align 8;"                                 \
@@ -41,7 +41,7 @@
        ({                                                      \
                unsigned long __v;                              \
                asm("1: " #inst " %0, %1;"                      \
-                   ".pushsection .coldtext.memcpy,\"ax\";"     \
+                   ".pushsection .coldtext,\"ax\";"    \
                    "2: { move r0, %2; jrp lr };"               \
                    ".section __ex_table,\"a\";"                \
                    ".align 8;"                                 \
index 3d63ff6f583ff406c98bce4014900669cec513bf..149ec55f9c46abd97cbb9b69c7a55afa23e23393 100644 (file)
@@ -16,6 +16,7 @@ generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
 generic-y += mutex.h
 generic-y += param.h
 generic-y += pci.h
diff --git a/arch/um/include/asm/mm-arch-hooks.h b/arch/um/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index a7c8b0d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_UM_MM_ARCH_HOOKS_H
-#define _ASM_UM_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_UM_MM_ARCH_HOOKS_H */
index d12b377b5a8b6b8e8cea9c9df92eef250ed3bf49..1fc7a286dc6f342319ec06a81b53a087b9708ef9 100644 (file)
@@ -26,6 +26,7 @@ generic-y += kdebug.h
 generic-y += kmap_types.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
diff --git a/arch/unicore32/include/asm/mm-arch-hooks.h b/arch/unicore32/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 4d79a85..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_UNICORE32_MM_ARCH_HOOKS_H
-#define _ASM_UNICORE32_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_UNICORE32_MM_ARCH_HOOKS_H */
index 55bced17dc95a475194f624d0e259fcaee3f8c8a..b3a1a5d77d92c2fd1d1d1a3b0b0b898944e8cd5b 100644 (file)
@@ -41,6 +41,7 @@ config X86
        select ARCH_USE_CMPXCHG_LOCKREF         if X86_64
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_USE_QUEUED_SPINLOCKS
+       select ARCH_WANTS_DYNAMIC_TASK_STRUCT
        select ARCH_WANT_FRAME_POINTERS
        select ARCH_WANT_IPC_PARSE_VERSION      if X86_32
        select ARCH_WANT_OPTIONAL_GPIOLIB
@@ -254,6 +255,11 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
 
+config KASAN_SHADOW_OFFSET
+       hex
+       depends on KASAN
+       default 0xdffffc0000000000
+
 config HAVE_INTEL_TXT
        def_bool y
        depends on INTEL_IOMMU && ACPI
@@ -2015,7 +2021,7 @@ config CMDLINE_BOOL
 
          To compile command line arguments into the kernel,
          set this option to 'Y', then fill in the
-         the boot arguments in CONFIG_CMDLINE.
+         boot arguments in CONFIG_CMDLINE.
 
          Systems with fully functional boot loaders (i.e. non-embedded)
          should leave this option set to 'N'.
index a15893d17c55988b542ad362f8c0074958130587..d8c0d3266173d96f84ac543885ba0bd63c0c3e47 100644 (file)
@@ -297,6 +297,18 @@ config OPTIMIZE_INLINING
 
          If unsure, say N.
 
+config DEBUG_ENTRY
+       bool "Debug low-level entry code"
+       depends on DEBUG_KERNEL
+       ---help---
+         This option enables sanity checks in x86's low-level entry code.
+         Some of these sanity checks may slow down kernel entries and
+         exits or otherwise impact performance.
+
+         This is currently used to help test NMI code.
+
+         If unsure, say N.
+
 config DEBUG_NMI_SELFTEST
        bool "NMI Selftest"
        depends on DEBUG_KERNEL && X86_LOCAL_APIC
index 2c82bd150d43546d03d01de07ecc8e43f5a459d8..7d69afd8b6fa47dab5478ce4c8d831ae6780881a 100644 (file)
@@ -1193,6 +1193,10 @@ static efi_status_t setup_e820(struct boot_params *params,
                unsigned int e820_type = 0;
                unsigned long m = efi->efi_memmap;
 
+#ifdef CONFIG_X86_64
+               m |= (u64)efi->efi_memmap_hi << 32;
+#endif
+
                d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
                switch (d->type) {
                case EFI_RESERVED_TYPE:
index 3bb2c4302df1f8ba18e21b997fd5b51e8ec55c54..8cb3e438f21e8558aad8d5b409af181fabaaf5ad 100644 (file)
@@ -1237,11 +1237,12 @@ ENTRY(nmi)
         *  If the variable is not set and the stack is not the NMI
         *  stack then:
         *    o Set the special variable on the stack
-        *    o Copy the interrupt frame into a "saved" location on the stack
-        *    o Copy the interrupt frame into a "copy" location on the stack
+        *    o Copy the interrupt frame into an "outermost" location on the
+        *      stack
+        *    o Copy the interrupt frame into an "iret" location on the stack
         *    o Continue processing the NMI
         *  If the variable is set or the previous stack is the NMI stack:
-        *    o Modify the "copy" location to jump to the repeate_nmi
+        *    o Modify the "iret" location to jump to the repeat_nmi
         *    o return back to the first NMI
         *
         * Now on exit of the first NMI, we first clear the stack variable
@@ -1250,31 +1251,151 @@ ENTRY(nmi)
         * a nested NMI that updated the copy interrupt stack frame, a
         * jump will be made to the repeat_nmi code that will handle the second
         * NMI.
+        *
+        * However, espfix prevents us from directly returning to userspace
+        * with a single IRET instruction.  Similarly, IRET to user mode
+        * can fault.  We therefore handle NMIs from user space like
+        * other IST entries.
         */
 
        /* Use %rdx as our temp variable throughout */
        pushq   %rdx
 
+       testb   $3, CS-RIP+8(%rsp)
+       jz      .Lnmi_from_kernel
+
+       /*
+        * NMI from user mode.  We need to run on the thread stack, but we
+        * can't go through the normal entry paths: NMIs are masked, and
+        * we don't want to enable interrupts, because then we'll end
+        * up in an awkward situation in which IRQs are on but NMIs
+        * are off.
+        */
+
+       SWAPGS
+       cld
+       movq    %rsp, %rdx
+       movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
+       pushq   5*8(%rdx)       /* pt_regs->ss */
+       pushq   4*8(%rdx)       /* pt_regs->rsp */
+       pushq   3*8(%rdx)       /* pt_regs->flags */
+       pushq   2*8(%rdx)       /* pt_regs->cs */
+       pushq   1*8(%rdx)       /* pt_regs->rip */
+       pushq   $-1             /* pt_regs->orig_ax */
+       pushq   %rdi            /* pt_regs->di */
+       pushq   %rsi            /* pt_regs->si */
+       pushq   (%rdx)          /* pt_regs->dx */
+       pushq   %rcx            /* pt_regs->cx */
+       pushq   %rax            /* pt_regs->ax */
+       pushq   %r8             /* pt_regs->r8 */
+       pushq   %r9             /* pt_regs->r9 */
+       pushq   %r10            /* pt_regs->r10 */
+       pushq   %r11            /* pt_regs->r11 */
+       pushq   %rbx            /* pt_regs->rbx */
+       pushq   %rbp            /* pt_regs->rbp */
+       pushq   %r12            /* pt_regs->r12 */
+       pushq   %r13            /* pt_regs->r13 */
+       pushq   %r14            /* pt_regs->r14 */
+       pushq   %r15            /* pt_regs->r15 */
+
+       /*
+        * At this point we no longer need to worry about stack damage
+        * due to nesting -- we're on the normal thread stack and we're
+        * done with the NMI stack.
+        */
+
+       movq    %rsp, %rdi
+       movq    $-1, %rsi
+       call    do_nmi
+
+       /*
+        * Return back to user mode.  We must *not* do the normal exit
+        * work, because we don't want to enable interrupts.  Fortunately,
+        * do_nmi doesn't modify pt_regs.
+        */
+       SWAPGS
+       jmp     restore_c_regs_and_iret
+
+.Lnmi_from_kernel:
+       /*
+        * Here's what our stack frame will look like:
+        * +---------------------------------------------------------+
+        * | original SS                                             |
+        * | original Return RSP                                     |
+        * | original RFLAGS                                         |
+        * | original CS                                             |
+        * | original RIP                                            |
+        * +---------------------------------------------------------+
+        * | temp storage for rdx                                    |
+        * +---------------------------------------------------------+
+        * | "NMI executing" variable                                |
+        * +---------------------------------------------------------+
+        * | iret SS          } Copied from "outermost" frame        |
+        * | iret Return RSP  } on each loop iteration; overwritten  |
+        * | iret RFLAGS      } by a nested NMI to force another     |
+        * | iret CS          } iteration if needed.                 |
+        * | iret RIP         }                                      |
+        * +---------------------------------------------------------+
+        * | outermost SS          } initialized in first_nmi;       |
+        * | outermost Return RSP  } will not be changed before      |
+        * | outermost RFLAGS      } NMI processing is done.         |
+        * | outermost CS          } Copied to "iret" frame on each  |
+        * | outermost RIP         } iteration.                      |
+        * +---------------------------------------------------------+
+        * | pt_regs                                                 |
+        * +---------------------------------------------------------+
+        *
+        * The "original" frame is used by hardware.  Before re-enabling
+        * NMIs, we need to be done with it, and we need to leave enough
+        * space for the asm code here.
+        *
+        * We return by executing IRET while RSP points to the "iret" frame.
+        * That will either return for real or it will loop back into NMI
+        * processing.
+        *
+        * The "outermost" frame is copied to the "iret" frame on each
+        * iteration of the loop, so each iteration starts with the "iret"
+        * frame pointing to the final return target.
+        */
+
        /*
-        * If %cs was not the kernel segment, then the NMI triggered in user
-        * space, which means it is definitely not nested.
+        * Determine whether we're a nested NMI.
+        *
+        * If we interrupted kernel code between repeat_nmi and
+        * end_repeat_nmi, then we are a nested NMI.  We must not
+        * modify the "iret" frame because it's being written by
+        * the outer NMI.  That's okay; the outer NMI handler is
+        * about to about to call do_nmi anyway, so we can just
+        * resume the outer NMI.
         */
-       cmpl    $__KERNEL_CS, 16(%rsp)
-       jne     first_nmi
+
+       movq    $repeat_nmi, %rdx
+       cmpq    8(%rsp), %rdx
+       ja      1f
+       movq    $end_repeat_nmi, %rdx
+       cmpq    8(%rsp), %rdx
+       ja      nested_nmi_out
+1:
 
        /*
-        * Check the special variable on the stack to see if NMIs are
-        * executing.
+        * Now check "NMI executing".  If it's set, then we're nested.
+        * This will not detect if we interrupted an outer NMI just
+        * before IRET.
         */
        cmpl    $1, -8(%rsp)
        je      nested_nmi
 
        /*
-        * Now test if the previous stack was an NMI stack.
-        * We need the double check. We check the NMI stack to satisfy the
-        * race when the first NMI clears the variable before returning.
-        * We check the variable because the first NMI could be in a
-        * breakpoint routine using a breakpoint stack.
+        * Now test if the previous stack was an NMI stack.  This covers
+        * the case where we interrupt an outer NMI after it clears
+        * "NMI executing" but before IRET.  We need to be careful, though:
+        * there is one case in which RSP could point to the NMI stack
+        * despite there being no NMI active: naughty userspace controls
+        * RSP at the very beginning of the SYSCALL targets.  We can
+        * pull a fast one on naughty userspace, though: we program
+        * SYSCALL to mask DF, so userspace cannot cause DF to be set
+        * if it controls the kernel's RSP.  We set DF before we clear
+        * "NMI executing".
         */
        lea     6*8(%rsp), %rdx
        /* Compare the NMI stack (rdx) with the stack we came from (4*8(%rsp)) */
@@ -1286,25 +1407,20 @@ ENTRY(nmi)
        cmpq    %rdx, 4*8(%rsp)
        /* If it is below the NMI stack, it is a normal NMI */
        jb      first_nmi
-       /* Ah, it is within the NMI stack, treat it as nested */
+
+       /* Ah, it is within the NMI stack. */
+
+       testb   $(X86_EFLAGS_DF >> 8), (3*8 + 1)(%rsp)
+       jz      first_nmi       /* RSP was user controlled. */
+
+       /* This is a nested NMI. */
 
 nested_nmi:
        /*
-        * Do nothing if we interrupted the fixup in repeat_nmi.
-        * It's about to repeat the NMI handler, so we are fine
-        * with ignoring this one.
+        * Modify the "iret" frame to point to repeat_nmi, forcing another
+        * iteration of NMI handling.
         */
-       movq    $repeat_nmi, %rdx
-       cmpq    8(%rsp), %rdx
-       ja      1f
-       movq    $end_repeat_nmi, %rdx
-       cmpq    8(%rsp), %rdx
-       ja      nested_nmi_out
-
-1:
-       /* Set up the interrupted NMIs stack to jump to repeat_nmi */
-       leaq    -1*8(%rsp), %rdx
-       movq    %rdx, %rsp
+       subq    $8, %rsp
        leaq    -10*8(%rsp), %rdx
        pushq   $__KERNEL_DS
        pushq   %rdx
@@ -1318,61 +1434,42 @@ nested_nmi:
 nested_nmi_out:
        popq    %rdx
 
-       /* No need to check faults here */
+       /* We are returning to kernel mode, so this cannot result in a fault. */
        INTERRUPT_RETURN
 
 first_nmi:
-       /*
-        * Because nested NMIs will use the pushed location that we
-        * stored in rdx, we must keep that space available.
-        * Here's what our stack frame will look like:
-        * +-------------------------+
-        * | original SS             |
-        * | original Return RSP     |
-        * | original RFLAGS         |
-        * | original CS             |
-        * | original RIP            |
-        * +-------------------------+
-        * | temp storage for rdx    |
-        * +-------------------------+
-        * | NMI executing variable  |
-        * +-------------------------+
-        * | copied SS               |
-        * | copied Return RSP       |
-        * | copied RFLAGS           |
-        * | copied CS               |
-        * | copied RIP              |
-        * +-------------------------+
-        * | Saved SS                |
-        * | Saved Return RSP        |
-        * | Saved RFLAGS            |
-        * | Saved CS                |
-        * | Saved RIP               |
-        * +-------------------------+
-        * | pt_regs                 |
-        * +-------------------------+
-        *
-        * The saved stack frame is used to fix up the copied stack frame
-        * that a nested NMI may change to make the interrupted NMI iret jump
-        * to the repeat_nmi. The original stack frame and the temp storage
-        * is also used by nested NMIs and can not be trusted on exit.
-        */
-       /* Do not pop rdx, nested NMIs will corrupt that part of the stack */
+       /* Restore rdx. */
        movq    (%rsp), %rdx
 
-       /* Set the NMI executing variable on the stack. */
-       pushq   $1
+       /* Make room for "NMI executing". */
+       pushq   $0
 
-       /* Leave room for the "copied" frame */
+       /* Leave room for the "iret" frame */
        subq    $(5*8), %rsp
 
-       /* Copy the stack frame to the Saved frame */
+       /* Copy the "original" frame to the "outermost" frame */
        .rept 5
        pushq   11*8(%rsp)
        .endr
 
        /* Everything up to here is safe from nested NMIs */
 
+#ifdef CONFIG_DEBUG_ENTRY
+       /*
+        * For ease of testing, unmask NMIs right away.  Disabled by
+        * default because IRET is very expensive.
+        */
+       pushq   $0              /* SS */
+       pushq   %rsp            /* RSP (minus 8 because of the previous push) */
+       addq    $8, (%rsp)      /* Fix up RSP */
+       pushfq                  /* RFLAGS */
+       pushq   $__KERNEL_CS    /* CS */
+       pushq   $1f             /* RIP */
+       INTERRUPT_RETURN        /* continues at repeat_nmi below */
+1:
+#endif
+
+repeat_nmi:
        /*
         * If there was a nested NMI, the first NMI's iret will return
         * here. But NMIs are still enabled and we can take another
@@ -1381,16 +1478,20 @@ first_nmi:
         * it will just return, as we are about to repeat an NMI anyway.
         * This makes it safe to copy to the stack frame that a nested
         * NMI will update.
+        *
+        * RSP is pointing to "outermost RIP".  gsbase is unknown, but, if
+        * we're repeating an NMI, gsbase has the same value that it had on
+        * the first iteration.  paranoid_entry will load the kernel
+        * gsbase if needed before we call do_nmi.  "NMI executing"
+        * is zero.
         */
-repeat_nmi:
+       movq    $1, 10*8(%rsp)          /* Set "NMI executing". */
+
        /*
-        * Update the stack variable to say we are still in NMI (the update
-        * is benign for the non-repeat case, where 1 was pushed just above
-        * to this very stack slot).
+        * Copy the "outermost" frame to the "iret" frame.  NMIs that nest
+        * here must not modify the "iret" frame while we're writing to
+        * it or it will end up containing garbage.
         */
-       movq    $1, 10*8(%rsp)
-
-       /* Make another copy, this one may be modified by nested NMIs */
        addq    $(10*8), %rsp
        .rept 5
        pushq   -6*8(%rsp)
@@ -1399,9 +1500,9 @@ repeat_nmi:
 end_repeat_nmi:
 
        /*
-        * Everything below this point can be preempted by a nested
-        * NMI if the first NMI took an exception and reset our iret stack
-        * so that we repeat another NMI.
+        * Everything below this point can be preempted by a nested NMI.
+        * If this happens, then the inner NMI will change the "iret"
+        * frame to point back to repeat_nmi.
         */
        pushq   $-1                             /* ORIG_RAX: no syscall to restart */
        ALLOC_PT_GPREGS_ON_STACK
@@ -1415,28 +1516,11 @@ end_repeat_nmi:
         */
        call    paranoid_entry
 
-       /*
-        * Save off the CR2 register. If we take a page fault in the NMI then
-        * it could corrupt the CR2 value. If the NMI preempts a page fault
-        * handler before it was able to read the CR2 register, and then the
-        * NMI itself takes a page fault, the page fault that was preempted
-        * will read the information from the NMI page fault and not the
-        * origin fault. Save it off and restore it if it changes.
-        * Use the r12 callee-saved register.
-        */
-       movq    %cr2, %r12
-
        /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
        movq    %rsp, %rdi
        movq    $-1, %rsi
        call    do_nmi
 
-       /* Did the NMI take a page fault? Restore cr2 if it did */
-       movq    %cr2, %rcx
-       cmpq    %rcx, %r12
-       je      1f
-       movq    %r12, %cr2
-1:
        testl   %ebx, %ebx                      /* swapgs needed? */
        jnz     nmi_restore
 nmi_swapgs:
@@ -1444,11 +1528,26 @@ nmi_swapgs:
 nmi_restore:
        RESTORE_EXTRA_REGS
        RESTORE_C_REGS
-       /* Pop the extra iret frame at once */
+
+       /* Point RSP at the "iret" frame. */
        REMOVE_PT_GPREGS_FROM_STACK 6*8
 
-       /* Clear the NMI executing stack variable */
-       movq    $0, 5*8(%rsp)
+       /*
+        * Clear "NMI executing".  Set DF first so that we can easily
+        * distinguish the remaining code between here and IRET from
+        * the SYSCALL entry and exit paths.  On a native kernel, we
+        * could just inspect RIP, but, on paravirt kernels,
+        * INTERRUPT_RETURN can translate into a jump into a
+        * hypercall page.
+        */
+       std
+       movq    $0, 5*8(%rsp)           /* clear "NMI executing" */
+
+       /*
+        * INTERRUPT_RETURN reads the "iret" frame and exits the NMI
+        * stack in a single instruction.  We are returning to kernel
+        * mode, so this cannot result in a fault.
+        */
        INTERRUPT_RETURN
 END(nmi)
 
index bb187a6a877cc62666afb43421eb7e5e8b6fbbfe..a7e257d9cb90b9f34ecb03180fec8c54f2afd82f 100644 (file)
@@ -140,6 +140,7 @@ sysexit_from_sys_call:
         */
        andl    $~TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
        movl    RIP(%rsp), %ecx         /* User %eip */
+       movq    RAX(%rsp), %rax
        RESTORE_RSI_RDI
        xorl    %edx, %edx              /* Do not leak kernel information */
        xorq    %r8, %r8
@@ -205,7 +206,6 @@ sysexit_from_sys_call:
        movl    RDX(%rsp), %edx         /* arg3 */
        movl    RSI(%rsp), %ecx         /* arg4 */
        movl    RDI(%rsp), %r8d         /* arg5 */
-       movl    %ebp, %r9d              /* arg6 */
        .endm
 
        .macro auditsys_exit exit
@@ -220,7 +220,6 @@ sysexit_from_sys_call:
 1:     setbe   %al                     /* 1 if error, 0 if not */
        movzbl  %al, %edi               /* zero-extend that into %edi */
        call    __audit_syscall_exit
-       movq    RAX(%rsp), %rax         /* reload syscall return value */
        movl    $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT), %edi
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
@@ -236,6 +235,7 @@ sysexit_from_sys_call:
 
 sysenter_auditsys:
        auditsys_entry_common
+       movl    %ebp, %r9d              /* reload 6th syscall arg */
        jmp     sysenter_dispatch
 
 sysexit_audit:
@@ -336,7 +336,7 @@ ENTRY(entry_SYSCALL_compat)
         * 32-bit zero extended:
         */
        ASM_STAC
-1:     movl    (%r8), %ebp
+1:     movl    (%r8), %r9d
        _ASM_EXTABLE(1b, ia32_badarg)
        ASM_CLAC
        orl     $TS_COMPAT, ASM_THREAD_INFO(TI_status, %rsp, SIZEOF_PTREGS)
@@ -346,7 +346,7 @@ ENTRY(entry_SYSCALL_compat)
 cstar_do_call:
        /* 32-bit syscall -> 64-bit C ABI argument conversion */
        movl    %edi, %r8d              /* arg5 */
-       movl    %ebp, %r9d              /* arg6 */
+       /* r9 already loaded */         /* arg6 */
        xchg    %ecx, %esi              /* rsi:arg2, rcx:arg4 */
        movl    %ebx, %edi              /* arg1 */
        movl    %edx, %edx              /* arg3 (zero extension) */
@@ -358,7 +358,6 @@ cstar_dispatch:
        call    *ia32_sys_call_table(, %rax, 8)
        movq    %rax, RAX(%rsp)
 1:
-       movl    RCX(%rsp), %ebp
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
        testl   $_TIF_ALLWORK_MASK, ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
@@ -369,6 +368,7 @@ sysretl_from_sys_call:
        RESTORE_RSI_RDI_RDX
        movl    RIP(%rsp), %ecx
        movl    EFLAGS(%rsp), %r11d
+       movq    RAX(%rsp), %rax
        xorq    %r10, %r10
        xorq    %r9, %r9
        xorq    %r8, %r8
@@ -392,7 +392,9 @@ sysretl_from_sys_call:
 
 #ifdef CONFIG_AUDITSYSCALL
 cstar_auditsys:
+       movl    %r9d, R9(%rsp)          /* register to be clobbered by call */
        auditsys_entry_common
+       movl    R9(%rsp), %r9d          /* reload 6th syscall arg */
        jmp     cstar_dispatch
 
 sysretl_audit:
@@ -404,14 +406,16 @@ cstar_tracesys:
        testl   $(_TIF_WORK_SYSCALL_ENTRY & ~_TIF_SYSCALL_AUDIT), ASM_THREAD_INFO(TI_flags, %rsp, SIZEOF_PTREGS)
        jz      cstar_auditsys
 #endif
+       xchgl   %r9d, %ebp
        SAVE_EXTRA_REGS
        xorl    %eax, %eax              /* Do not leak kernel information */
        movq    %rax, R11(%rsp)
        movq    %rax, R10(%rsp)
-       movq    %rax, R9(%rsp)
+       movq    %r9, R9(%rsp)
        movq    %rax, R8(%rsp)
        movq    %rsp, %rdi              /* &pt_regs -> arg1 */
        call    syscall_trace_enter
+       movl    R9(%rsp), %r9d
 
        /* Reload arg registers from stack. (see sysenter_tracesys) */
        movl    RCX(%rsp), %ecx
@@ -421,6 +425,7 @@ cstar_tracesys:
        movl    %eax, %eax              /* zero extension */
 
        RESTORE_EXTRA_REGS
+       xchgl   %ebp, %r9d
        jmp     cstar_do_call
 END(entry_SYSCALL_compat)
 
index 4dd1f2d770af41f6d9c16688af6c0c65b2d9554d..aeac434c9febd6e6cd4b5c595288e4b2eb2c9f12 100644 (file)
@@ -9,3 +9,4 @@ generic-y += cputime.h
 generic-y += dma-contiguous.h
 generic-y += early_ioremap.h
 generic-y += mcs_spinlock.h
+generic-y += mm-arch-hooks.h
index a0bf89fd26470102f6f38031808437f01afe8e1f..4e10d73cf01844edc201ed23f51d28a72a537521 100644 (file)
@@ -280,21 +280,6 @@ static inline void clear_LDT(void)
        set_ldt(NULL, 0);
 }
 
-/*
- * load one particular LDT into the current CPU
- */
-static inline void load_LDT_nolock(mm_context_t *pc)
-{
-       set_ldt(pc->ldt, pc->size);
-}
-
-static inline void load_LDT(mm_context_t *pc)
-{
-       preempt_disable();
-       load_LDT_nolock(pc);
-       preempt_enable();
-}
-
 static inline unsigned long get_desc_base(const struct desc_struct *desc)
 {
        return (unsigned)(desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24));
index 99efebb2f69df5fd5a9d9fdf1a37c6a15ac38dd1..ca3ce9ab9385336cec07258c87d05c6eb5580740 100644 (file)
@@ -9,7 +9,7 @@ DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
 DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
 
 extern void init_espfix_bsp(void);
-extern void init_espfix_ap(void);
+extern void init_espfix_ap(int cpu);
 
 #endif /* CONFIG_X86_64 */
 
index 0637826292deae64c7e6f0cbe10f4a6af2056cd5..c49c5173158e743b985c4e29f09f040811db6a48 100644 (file)
@@ -189,6 +189,7 @@ union fpregs_state {
        struct fxregs_state             fxsave;
        struct swregs_state             soft;
        struct xregs_state              xsave;
+       u8 __padding[PAGE_SIZE];
 };
 
 /*
@@ -197,40 +198,6 @@ union fpregs_state {
  * state fields:
  */
 struct fpu {
-       /*
-        * @state:
-        *
-        * In-memory copy of all FPU registers that we save/restore
-        * over context switches. If the task is using the FPU then
-        * the registers in the FPU are more recent than this state
-        * copy. If the task context-switches away then they get
-        * saved here and represent the FPU state.
-        *
-        * After context switches there may be a (short) time period
-        * during which the in-FPU hardware registers are unchanged
-        * and still perfectly match this state, if the tasks
-        * scheduled afterwards are not using the FPU.
-        *
-        * This is the 'lazy restore' window of optimization, which
-        * we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'.
-        *
-        * We detect whether a subsequent task uses the FPU via setting
-        * CR0::TS to 1, which causes any FPU use to raise a #NM fault.
-        *
-        * During this window, if the task gets scheduled again, we
-        * might be able to skip having to do a restore from this
-        * memory buffer to the hardware registers - at the cost of
-        * incurring the overhead of #NM fault traps.
-        *
-        * Note that on modern CPUs that support the XSAVEOPT (or other
-        * optimized XSAVE instructions), we don't use #NM traps anymore,
-        * as the hardware can track whether FPU registers need saving
-        * or not. On such CPUs we activate the non-lazy ('eagerfpu')
-        * logic, which unconditionally saves/restores all FPU state
-        * across context switches. (if FPU state exists.)
-        */
-       union fpregs_state              state;
-
        /*
         * @last_cpu:
         *
@@ -288,6 +255,43 @@ struct fpu {
         * deal with bursty apps that only use the FPU for a short time:
         */
        unsigned char                   counter;
+       /*
+        * @state:
+        *
+        * In-memory copy of all FPU registers that we save/restore
+        * over context switches. If the task is using the FPU then
+        * the registers in the FPU are more recent than this state
+        * copy. If the task context-switches away then they get
+        * saved here and represent the FPU state.
+        *
+        * After context switches there may be a (short) time period
+        * during which the in-FPU hardware registers are unchanged
+        * and still perfectly match this state, if the tasks
+        * scheduled afterwards are not using the FPU.
+        *
+        * This is the 'lazy restore' window of optimization, which
+        * we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'.
+        *
+        * We detect whether a subsequent task uses the FPU via setting
+        * CR0::TS to 1, which causes any FPU use to raise a #NM fault.
+        *
+        * During this window, if the task gets scheduled again, we
+        * might be able to skip having to do a restore from this
+        * memory buffer to the hardware registers - at the cost of
+        * incurring the overhead of #NM fault traps.
+        *
+        * Note that on modern CPUs that support the XSAVEOPT (or other
+        * optimized XSAVE instructions), we don't use #NM traps anymore,
+        * as the hardware can track whether FPU registers need saving
+        * or not. On such CPUs we activate the non-lazy ('eagerfpu')
+        * logic, which unconditionally saves/restores all FPU state
+        * across context switches. (if FPU state exists.)
+        */
+       union fpregs_state              state;
+       /*
+        * WARNING: 'state' is dynamically-sized.  Do not put
+        * anything after it here.
+        */
 };
 
 #endif /* _ASM_X86_FPU_H */
index 200ec2e7821d1922cb1f15ddaaf836e064dc025e..cd0310e186f4af534b7e21312b81d092ff9ba8cd 100644 (file)
 
 #if IS_ENABLED(CONFIG_INTEL_PMC_IPC)
 
-/*
- * intel_pmc_ipc_simple_command
- * @cmd: command
- * @sub: sub type
- */
 int intel_pmc_ipc_simple_command(int cmd, int sub);
-
-/*
- * intel_pmc_ipc_raw_cmd
- * @cmd: command
- * @sub: sub type
- * @in: input data
- * @inlen: input length in bytes
- * @out: output data
- * @outlen: output length in dwords
- * @sptr: data writing to SPTR register
- * @dptr: data writing to DPTR register
- */
 int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
                u32 *out, u32 outlen, u32 dptr, u32 sptr);
-
-/*
- * intel_pmc_ipc_command
- * @cmd: command
- * @sub: sub type
- * @in: input data
- * @inlen: input length in bytes
- * @out: output data
- * @outlen: output length in dwords
- */
 int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
                u32 *out, u32 outlen);
 
index 8b22422fbad8ad97cd7affcabc432a72e5cda883..74a2a8dc99089ddbcefb833e671f6a5f6d1ed1e0 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-extern pte_t kasan_zero_pte[];
-extern pte_t kasan_zero_pmd[];
-extern pte_t kasan_zero_pud[];
-
 #ifdef CONFIG_KASAN
-void __init kasan_map_early_shadow(pgd_t *pgd);
+void __init kasan_early_init(void);
 void __init kasan_init(void);
 #else
-static inline void kasan_map_early_shadow(pgd_t *pgd) { }
+static inline void kasan_early_init(void) { }
 static inline void kasan_init(void) { }
 #endif
 
index 2a7f5d782c332d1965ac1c5a23a33289cfce7352..49ec9038ec14102a286c9b4bed126a6825613439 100644 (file)
@@ -604,6 +604,8 @@ struct kvm_arch {
        bool iommu_noncoherent;
 #define __KVM_HAVE_ARCH_NONCOHERENT_DMA
        atomic_t noncoherent_dma_count;
+#define __KVM_HAVE_ARCH_ASSIGNED_DEVICE
+       atomic_t assigned_device_count;
        struct kvm_pic *vpic;
        struct kvm_ioapic *vioapic;
        struct kvm_pit *vpit;
diff --git a/arch/x86/include/asm/mm-arch-hooks.h b/arch/x86/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index 4e881a3..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_X86_MM_ARCH_HOOKS_H
-#define _ASM_X86_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_X86_MM_ARCH_HOOKS_H */
index 09b9620a73b4841893fc2bd01bfd614d43e7e214..364d27481a52a34f5031933ecc577af0ebf3c129 100644 (file)
@@ -9,8 +9,7 @@
  * we put the segment information here.
  */
 typedef struct {
-       void *ldt;
-       int size;
+       struct ldt_struct *ldt;
 
 #ifdef CONFIG_X86_64
        /* True if mm supports a task running in 32 bit compatibility mode. */
index 5e8daee7c5c94be6fc48bc7f32e593fb46948557..984abfe47edc85db7b1a1809d5e0b2d22a7c0449 100644 (file)
@@ -23,7 +23,7 @@ extern struct static_key rdpmc_always_available;
 
 static inline void load_mm_cr4(struct mm_struct *mm)
 {
-       if (static_key_true(&rdpmc_always_available) ||
+       if (static_key_false(&rdpmc_always_available) ||
            atomic_read(&mm->context.perf_rdpmc_allowed))
                cr4_set_bits(X86_CR4_PCE);
        else
@@ -33,6 +33,50 @@ static inline void load_mm_cr4(struct mm_struct *mm)
 static inline void load_mm_cr4(struct mm_struct *mm) {}
 #endif
 
+/*
+ * ldt_structs can be allocated, used, and freed, but they are never
+ * modified while live.
+ */
+struct ldt_struct {
+       /*
+        * Xen requires page-aligned LDTs with special permissions.  This is
+        * needed to prevent us from installing evil descriptors such as
+        * call gates.  On native, we could merge the ldt_struct and LDT
+        * allocations, but it's not worth trying to optimize.
+        */
+       struct desc_struct *entries;
+       int size;
+};
+
+static inline void load_mm_ldt(struct mm_struct *mm)
+{
+       struct ldt_struct *ldt;
+
+       /* lockless_dereference synchronizes with smp_store_release */
+       ldt = lockless_dereference(mm->context.ldt);
+
+       /*
+        * Any change to mm->context.ldt is followed by an IPI to all
+        * CPUs with the mm active.  The LDT will not be freed until
+        * after the IPI is handled by all such CPUs.  This means that,
+        * if the ldt_struct changes before we return, the values we see
+        * will be safe, and the new values will be loaded before we run
+        * any user code.
+        *
+        * NB: don't try to convert this to use RCU without extreme care.
+        * We would still need IRQs off, because we don't want to change
+        * the local LDT after an IPI loaded a newer value than the one
+        * that we can see.
+        */
+
+       if (unlikely(ldt))
+               set_ldt(ldt->entries, ldt->size);
+       else
+               clear_LDT();
+
+       DEBUG_LOCKS_WARN_ON(preemptible());
+}
+
 /*
  * Used for LDT copy/destruction.
  */
@@ -78,12 +122,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                 * was called and then modify_ldt changed
                 * prev->context.ldt but suppressed an IPI to this CPU.
                 * In this case, prev->context.ldt != NULL, because we
-                * never free an LDT while the mm still exists.  That
-                * means that next->context.ldt != prev->context.ldt,
-                * because mms never share an LDT.
+                * never set context.ldt to NULL while the mm still
+                * exists.  That means that next->context.ldt !=
+                * prev->context.ldt, because mms never share an LDT.
                 */
                if (unlikely(prev->context.ldt != next->context.ldt))
-                       load_LDT_nolock(&next->context);
+                       load_mm_ldt(next);
        }
 #ifdef CONFIG_SMP
          else {
@@ -106,7 +150,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                        load_cr3(next->pgd);
                        trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
                        load_mm_cr4(next);
-                       load_LDT_nolock(&next->context);
+                       load_mm_ldt(next);
                }
        }
 #endif
index 43e6519df0d507429a9533b51c7a28f2c0f3b90b..944f1785ed0dafac2a9a888e3aa75120d495eb70 100644 (file)
@@ -390,9 +390,6 @@ struct thread_struct {
 #endif
        unsigned long           gs;
 
-       /* Floating point and extended processor state */
-       struct fpu              fpu;
-
        /* Save middle states of ptrace breakpoints */
        struct perf_event       *ptrace_bps[HBP_NUM];
        /* Debug status used for traps, single steps, etc... */
@@ -418,6 +415,13 @@ struct thread_struct {
        unsigned long           iopl;
        /* Max allowed port in the bitmap, in bytes: */
        unsigned                io_bitmap_max;
+
+       /* Floating point and extended processor state */
+       struct fpu              fpu;
+       /*
+        * WARNING: 'fpu' is dynamically-sized.  It *MUST* be at
+        * the end.
+        */
 };
 
 /*
index 6fe6b182c9981dd891a9a5bc9a55b3e6591a6f9f..9dfce4e0417d92adc623d32ff93f67109316b451 100644 (file)
@@ -57,9 +57,9 @@ struct sigcontext {
        unsigned long ip;
        unsigned long flags;
        unsigned short cs;
-       unsigned short __pad2;  /* Was called gs, but was always zero. */
-       unsigned short __pad1;  /* Was called fs, but was always zero. */
-       unsigned short ss;
+       unsigned short gs;
+       unsigned short fs;
+       unsigned short __pad0;
        unsigned long err;
        unsigned long trapno;
        unsigned long oldmask;
index 751bf4b7bf114da12231a56f4217c2583ddeafb2..d7f3b3b78ac313ca8a871d3a53b3d118850a657d 100644 (file)
@@ -79,12 +79,12 @@ do {                                                                        \
 #else /* CONFIG_X86_32 */
 
 /* frame pointer must be last for get_wchan */
-#define SAVE_CONTEXT    "pushq %%rbp ; movq %%rsi,%%rbp\n\t"
-#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\t"
+#define SAVE_CONTEXT    "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
+#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
 
 #define __EXTRA_CLOBBER  \
        , "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
-         "r12", "r13", "r14", "r15", "flags"
+         "r12", "r13", "r14", "r15"
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 #define __switch_canary                                                          \
@@ -100,11 +100,7 @@ do {                                                                       \
 #define __switch_canary_iparam
 #endif /* CC_STACKPROTECTOR */
 
-/*
- * There is no need to save or restore flags, because flags are always
- * clean in kernel mode, with the possible exception of IOPL.  Kernel IOPL
- * has no effect.
- */
+/* Save restore flags to clear handle leaking NT */
 #define switch_to(prev, next, last) \
        asm volatile(SAVE_CONTEXT                                         \
             "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */       \
index 8fba544e9cc4164261f76c6c5d894b80a92f0377..f36d56bd76324543f6f0c208bea569ea96e6e802 100644 (file)
 #define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE          (1 << 4)
 /* Support for a virtual guest idle state is available */
 #define HV_X64_GUEST_IDLE_STATE_AVAILABLE              (1 << 5)
+/* Guest crash data handler available */
+#define HV_X64_GUEST_CRASH_MSR_AVAILABLE               (1 << 10)
 
 /*
  * Implementation recommendations. Indicates which behaviors the hypervisor
index a4ae82eb82aa8485146aee83376ba26fb9306afe..cd54147cb365fb3622121c782eee8e7fb3ddcc77 100644 (file)
@@ -354,7 +354,7 @@ struct kvm_xcrs {
 struct kvm_sync_regs {
 };
 
-#define KVM_QUIRK_LINT0_REENABLED      (1 << 0)
-#define KVM_QUIRK_CD_NW_CLEARED                (1 << 1)
+#define KVM_X86_QUIRK_LINT0_REENABLED  (1 << 0)
+#define KVM_X86_QUIRK_CD_NW_CLEARED    (1 << 1)
 
 #endif /* _ASM_X86_KVM_H */
index 0e8a973de9ee8aec0c555a5e9e8b23348e2cc10b..40836a9a7250c99a16dc5969057177f66aa57186 100644 (file)
@@ -177,24 +177,9 @@ struct sigcontext {
        __u64 rip;
        __u64 eflags;           /* RFLAGS */
        __u16 cs;
-
-       /*
-        * Prior to 2.5.64 ("[PATCH] x86-64 updates for 2.5.64-bk3"),
-        * Linux saved and restored fs and gs in these slots.  This
-        * was counterproductive, as fsbase and gsbase were never
-        * saved, so arch_prctl was presumably unreliable.
-        *
-        * If these slots are ever needed for any other purpose, there
-        * is some risk that very old 64-bit binaries could get
-        * confused.  I doubt that many such binaries still work,
-        * though, since the same patch in 2.5.64 also removed the
-        * 64-bit set_thread_area syscall, so it appears that there is
-        * no TLS API that works in both pre- and post-2.5.64 kernels.
-        */
-       __u16 __pad2;           /* Was gs. */
-       __u16 __pad1;           /* Was fs. */
-
-       __u16 ss;
+       __u16 gs;
+       __u16 fs;
+       __u16 __pad0;
        __u64 err;
        __u64 trapno;
        __u64 oldmask;
index 845dc0df2002472275a39e421502cdb0768c54a1..206052e5551702258a8c65f308fefaed2c988a07 100644 (file)
@@ -943,7 +943,7 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
         */
        if (irq < nr_legacy_irqs() && data->count == 1) {
                if (info->ioapic_trigger != data->trigger)
-                       mp_register_handler(irq, data->trigger);
+                       mp_register_handler(irq, info->ioapic_trigger);
                data->entry.trigger = data->trigger = info->ioapic_trigger;
                data->entry.polarity = data->polarity = info->ioapic_polarity;
        }
index 28eba2d38b1570c77f3b82543d6ee84686333027..2683f36e4e0a5e67311a7bcdbceea61c17382ec6 100644 (file)
@@ -322,7 +322,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
                irq_data->chip = &lapic_controller;
                irq_data->chip_data = data;
                irq_data->hwirq = virq + i;
-               err = assign_irq_vector_policy(virq, irq_data->node, data,
+               err = assign_irq_vector_policy(virq + i, irq_data->node, data,
                                               info);
                if (err)
                        goto error;
@@ -409,12 +409,6 @@ static void __setup_vector_irq(int cpu)
        int irq, vector;
        struct apic_chip_data *data;
 
-       /*
-        * vector_lock will make sure that we don't run into irq vector
-        * assignments that might be happening on another cpu in parallel,
-        * while we setup our initial vector to irq mappings.
-        */
-       raw_spin_lock(&vector_lock);
        /* Mark the inuse vectors */
        for_each_active_irq(irq) {
                data = apic_chip_data(irq_get_irq_data(irq));
@@ -436,16 +430,16 @@ static void __setup_vector_irq(int cpu)
                if (!cpumask_test_cpu(cpu, data->domain))
                        per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
        }
-       raw_spin_unlock(&vector_lock);
 }
 
 /*
- * Setup the vector to irq mappings.
+ * Setup the vector to irq mappings. Must be called with vector_lock held.
  */
 void setup_vector_irq(int cpu)
 {
        int irq;
 
+       lockdep_assert_held(&vector_lock);
        /*
         * On most of the platforms, legacy PIC delivers the interrupts on the
         * boot cpu. But there are certain platforms where PIC interrupts are
index 922c5e0cea4c961b1aa6e7a266ce588de7f7a300..cb9e5df42dd2464f7249eea78cc28753eb858ec0 100644 (file)
@@ -1410,7 +1410,7 @@ void cpu_init(void)
        load_sp0(t, &current->thread);
        set_tss_desc(cpu, t);
        load_TR_desc();
-       load_LDT(&init_mm.context);
+       load_mm_ldt(&init_mm);
 
        clear_all_debug_regs();
        dbg_restore_debug_regs();
@@ -1459,7 +1459,7 @@ void cpu_init(void)
        load_sp0(t, thread);
        set_tss_desc(cpu, t);
        load_TR_desc();
-       load_LDT(&init_mm.context);
+       load_mm_ldt(&init_mm);
 
        t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
 
index 3658de47900f9a921a0f8373db962e061d42db3a..9469dfa556074db4dff41212a4873b31d5907772 100644 (file)
@@ -2179,21 +2179,25 @@ static unsigned long get_segment_base(unsigned int segment)
        int idx = segment >> 3;
 
        if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+               struct ldt_struct *ldt;
+
                if (idx > LDT_ENTRIES)
                        return 0;
 
-               if (idx > current->active_mm->context.size)
+               /* IRQs are off, so this synchronizes with smp_store_release */
+               ldt = lockless_dereference(current->active_mm->context.ldt);
+               if (!ldt || idx > ldt->size)
                        return 0;
 
-               desc = current->active_mm->context.ldt;
+               desc = &ldt->entries[idx];
        } else {
                if (idx > GDT_ENTRIES)
                        return 0;
 
-               desc = raw_cpu_ptr(gdt_page.gdt);
+               desc = raw_cpu_ptr(gdt_page.gdt) + idx;
        }
 
-       return get_desc_base(desc + idx);
+       return get_desc_base(desc);
 }
 
 #ifdef CONFIG_COMPAT
index b9826a981fb20fa45a7c1255e277e9ad1cd5d150..6326ae24e4d5b4f3d228111c10f5c85df0e40d3f 100644 (file)
@@ -2534,7 +2534,7 @@ static int intel_pmu_cpu_prepare(int cpu)
        if (x86_pmu.extra_regs || x86_pmu.lbr_sel_map) {
                cpuc->shared_regs = allocate_shared_regs(cpu);
                if (!cpuc->shared_regs)
-                       return NOTIFY_BAD;
+                       goto err;
        }
 
        if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
@@ -2542,18 +2542,27 @@ static int intel_pmu_cpu_prepare(int cpu)
 
                cpuc->constraint_list = kzalloc(sz, GFP_KERNEL);
                if (!cpuc->constraint_list)
-                       return NOTIFY_BAD;
+                       goto err_shared_regs;
 
                cpuc->excl_cntrs = allocate_excl_cntrs(cpu);
-               if (!cpuc->excl_cntrs) {
-                       kfree(cpuc->constraint_list);
-                       kfree(cpuc->shared_regs);
-                       return NOTIFY_BAD;
-               }
+               if (!cpuc->excl_cntrs)
+                       goto err_constraint_list;
+
                cpuc->excl_thread_id = 0;
        }
 
        return NOTIFY_OK;
+
+err_constraint_list:
+       kfree(cpuc->constraint_list);
+       cpuc->constraint_list = NULL;
+
+err_shared_regs:
+       kfree(cpuc->shared_regs);
+       cpuc->shared_regs = NULL;
+
+err:
+       return NOTIFY_BAD;
 }
 
 static void intel_pmu_cpu_starting(int cpu)
index 188076161c1be51afe135d6289b8ce0e96952bf3..377e8f8ed39186ad4ef57b33264592ed8459a037 100644 (file)
@@ -951,6 +951,14 @@ static u64 intel_cqm_event_count(struct perf_event *event)
        if (!cqm_group_leader(event))
                return 0;
 
+       /*
+        * Getting up-to-date values requires an SMP IPI which is not
+        * possible if we're being called in interrupt context. Return
+        * the cached values instead.
+        */
+       if (unlikely(in_interrupt()))
+               goto out;
+
        /*
         * Notice that we don't perform the reading of an RMID
         * atomically, because we can't hold a spin lock across the
@@ -1247,7 +1255,7 @@ static inline void cqm_pick_event_reader(int cpu)
        cpumask_set_cpu(cpu, &cqm_cpumask);
 }
 
-static void intel_cqm_cpu_prepare(unsigned int cpu)
+static void intel_cqm_cpu_starting(unsigned int cpu)
 {
        struct intel_pqr_state *state = &per_cpu(pqr_state, cpu);
        struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -1288,13 +1296,11 @@ static int intel_cqm_cpu_notifier(struct notifier_block *nb,
        unsigned int cpu  = (unsigned long)hcpu;
 
        switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_UP_PREPARE:
-               intel_cqm_cpu_prepare(cpu);
-               break;
        case CPU_DOWN_PREPARE:
                intel_cqm_cpu_exit(cpu);
                break;
        case CPU_STARTING:
+               intel_cqm_cpu_starting(cpu);
                cqm_pick_event_reader(cpu);
                break;
        }
@@ -1365,7 +1371,7 @@ static int __init intel_cqm_init(void)
                goto out;
 
        for_each_online_cpu(i) {
-               intel_cqm_cpu_prepare(i);
+               intel_cqm_cpu_starting(i);
                cqm_pick_event_reader(i);
        }
 
index 89427d8d4fc53addcb429b994f02de7d0bb7dfa4..eec40f595ab97ee74b83002a21e09a0d2c032cbb 100644 (file)
@@ -175,7 +175,9 @@ static __init void early_serial_init(char *s)
        }
 
        if (*s) {
-               if (kstrtoul(s, 0, &baud) < 0 || baud == 0)
+               baud = simple_strtoull(s, &e, 0);
+
+               if (baud == 0 || s == e)
                        baud = DEFAULT_BAUD;
        }
 
index f5d0730e7b084beddefb0f4b8ff6755b9166535a..ce95676abd603d2590e258374931b9ad72305f29 100644 (file)
@@ -131,25 +131,24 @@ void __init init_espfix_bsp(void)
        init_espfix_random();
 
        /* The rest is the same as for any other processor */
-       init_espfix_ap();
+       init_espfix_ap(0);
 }
 
-void init_espfix_ap(void)
+void init_espfix_ap(int cpu)
 {
-       unsigned int cpu, page;
+       unsigned int page;
        unsigned long addr;
        pud_t pud, *pud_p;
        pmd_t pmd, *pmd_p;
        pte_t pte, *pte_p;
-       int n;
+       int n, node;
        void *stack_page;
        pteval_t ptemask;
 
        /* We only have to do this once... */
-       if (likely(this_cpu_read(espfix_stack)))
+       if (likely(per_cpu(espfix_stack, cpu)))
                return;         /* Already initialized */
 
-       cpu = smp_processor_id();
        addr = espfix_base_addr(cpu);
        page = cpu/ESPFIX_STACKS_PER_PAGE;
 
@@ -165,12 +164,15 @@ void init_espfix_ap(void)
        if (stack_page)
                goto unlock_done;
 
+       node = cpu_to_node(cpu);
        ptemask = __supported_pte_mask;
 
        pud_p = &espfix_pud_page[pud_index(addr)];
        pud = *pud_p;
        if (!pud_present(pud)) {
-               pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP);
+               struct page *page = alloc_pages_node(node, PGALLOC_GFP, 0);
+
+               pmd_p = (pmd_t *)page_address(page);
                pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask));
                paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT);
                for (n = 0; n < ESPFIX_PUD_CLONES; n++)
@@ -180,7 +182,9 @@ void init_espfix_ap(void)
        pmd_p = pmd_offset(&pud, addr);
        pmd = *pmd_p;
        if (!pmd_present(pmd)) {
-               pte_p = (pte_t *)__get_free_page(PGALLOC_GFP);
+               struct page *page = alloc_pages_node(node, PGALLOC_GFP, 0);
+
+               pte_p = (pte_t *)page_address(page);
                pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask));
                paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT);
                for (n = 0; n < ESPFIX_PMD_CLONES; n++)
@@ -188,7 +192,7 @@ void init_espfix_ap(void)
        }
 
        pte_p = pte_offset_kernel(&pmd, addr);
-       stack_page = (void *)__get_free_page(GFP_KERNEL);
+       stack_page = page_address(alloc_pages_node(node, GFP_KERNEL, 0));
        pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask));
        for (n = 0; n < ESPFIX_PTE_CLONES; n++)
                set_pte(&pte_p[n*PTE_STRIDE], pte);
@@ -199,7 +203,7 @@ void init_espfix_ap(void)
 unlock_done:
        mutex_unlock(&espfix_init_mutex);
 done:
-       this_cpu_write(espfix_stack, addr);
-       this_cpu_write(espfix_waddr, (unsigned long)stack_page
-                      + (addr & ~PAGE_MASK));
+       per_cpu(espfix_stack, cpu) = addr;
+       per_cpu(espfix_waddr, cpu) = (unsigned long)stack_page
+                                     + (addr & ~PAGE_MASK);
 }
index 79de954626fd971f1d24553078bed1f199d52267..d25097c3fc1d1af8af35c156f05121f9f4d46a94 100644 (file)
@@ -270,7 +270,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu)
        dst_fpu->fpregs_active = 0;
        dst_fpu->last_cpu = -1;
 
-       if (src_fpu->fpstate_active)
+       if (src_fpu->fpstate_active && cpu_has_fpu)
                fpu_copy(dst_fpu, src_fpu);
 
        return 0;
index 32826791e6757203b5440dad36f5e80b3fc8fbe9..d14e9ac3235a1ac73174ffb95b2990d5163d2933 100644 (file)
@@ -4,6 +4,8 @@
 #include <asm/fpu/internal.h>
 #include <asm/tlbflush.h>
 
+#include <linux/sched.h>
+
 /*
  * Initialize the TS bit in CR0 according to the style of context-switches
  * we are using:
@@ -38,7 +40,12 @@ static void fpu__init_cpu_generic(void)
        write_cr0(cr0);
 
        /* Flush out any pending x87 state: */
-       asm volatile ("fninit");
+#ifdef CONFIG_MATH_EMULATION
+       if (!cpu_has_fpu)
+               fpstate_init_soft(&current->thread.fpu.state.soft);
+       else
+#endif
+               asm volatile ("fninit");
 }
 
 /*
@@ -136,6 +143,43 @@ static void __init fpu__init_system_generic(void)
 unsigned int xstate_size;
 EXPORT_SYMBOL_GPL(xstate_size);
 
+/* Enforce that 'MEMBER' is the last field of 'TYPE': */
+#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
+       BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER))
+
+/*
+ * We append the 'struct fpu' to the task_struct:
+ */
+static void __init fpu__init_task_struct_size(void)
+{
+       int task_size = sizeof(struct task_struct);
+
+       /*
+        * Subtract off the static size of the register state.
+        * It potentially has a bunch of padding.
+        */
+       task_size -= sizeof(((struct task_struct *)0)->thread.fpu.state);
+
+       /*
+        * Add back the dynamically-calculated register state
+        * size.
+        */
+       task_size += xstate_size;
+
+       /*
+        * We dynamically size 'struct fpu', so we require that
+        * it be at the end of 'thread_struct' and that
+        * 'thread_struct' be at the end of 'task_struct'.  If
+        * you hit a compile error here, check the structure to
+        * see if something got added to the end.
+        */
+       CHECK_MEMBER_AT_END_OF(struct fpu, state);
+       CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu);
+       CHECK_MEMBER_AT_END_OF(struct task_struct, thread);
+
+       arch_task_struct_size = task_size;
+}
+
 /*
  * Set up the xstate_size based on the legacy FPU context size.
  *
@@ -287,6 +331,7 @@ void __init fpu__init_system(struct cpuinfo_x86 *c)
        fpu__init_system_generic();
        fpu__init_system_xstate_size_legacy();
        fpu__init_system_xstate();
+       fpu__init_task_struct_size();
 
        fpu__init_system_ctx_switch();
 }
@@ -311,9 +356,15 @@ static int __init x86_noxsave_setup(char *s)
 
        setup_clear_cpu_cap(X86_FEATURE_XSAVE);
        setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
+       setup_clear_cpu_cap(X86_FEATURE_XSAVEC);
        setup_clear_cpu_cap(X86_FEATURE_XSAVES);
        setup_clear_cpu_cap(X86_FEATURE_AVX);
        setup_clear_cpu_cap(X86_FEATURE_AVX2);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512F);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512PF);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512ER);
+       setup_clear_cpu_cap(X86_FEATURE_AVX512CD);
+       setup_clear_cpu_cap(X86_FEATURE_MPX);
 
        return 1;
 }
index 5a4668136e9892b6b8695d1d82edf86afbdea0a0..f129a9af635747ce616e354a43f30297f3fecabf 100644 (file)
@@ -161,11 +161,12 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
        /* Kill off the identity-map trampoline */
        reset_early_page_tables();
 
-       kasan_map_early_shadow(early_level4_pgt);
-
-       /* clear bss before set_intr_gate with early_idt_handler */
        clear_bss();
 
+       clear_page(init_level4_pgt);
+
+       kasan_early_init();
+
        for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
                set_intr_gate(i, early_idt_handler_array[i]);
        load_idt((const struct desc_ptr *)&idt_descr);
@@ -177,12 +178,9 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
         */
        load_ucode_bsp();
 
-       clear_page(init_level4_pgt);
        /* set init_level4_pgt kernel high mapping*/
        init_level4_pgt[511] = early_level4_pgt[511];
 
-       kasan_map_early_shadow(init_level4_pgt);
-
        x86_64_start_reservations(real_mode_data);
 }
 
index e5c27f729a3840b2755533cb597fbf702de07621..1d40ca8a73f27231e49c35704794d0cbe6ca94dc 100644 (file)
@@ -516,38 +516,9 @@ ENTRY(phys_base)
        /* This must match the first entry in level2_kernel_pgt */
        .quad   0x0000000000000000
 
-#ifdef CONFIG_KASAN
-#define FILL(VAL, COUNT)                               \
-       .rept (COUNT) ;                                 \
-       .quad   (VAL) ;                                 \
-       .endr
-
-NEXT_PAGE(kasan_zero_pte)
-       FILL(kasan_zero_page - __START_KERNEL_map + _KERNPG_TABLE, 512)
-NEXT_PAGE(kasan_zero_pmd)
-       FILL(kasan_zero_pte - __START_KERNEL_map + _KERNPG_TABLE, 512)
-NEXT_PAGE(kasan_zero_pud)
-       FILL(kasan_zero_pmd - __START_KERNEL_map + _KERNPG_TABLE, 512)
-
-#undef FILL
-#endif
-
-
 #include "../../x86/xen/xen-head.S"
        
        __PAGE_ALIGNED_BSS
 NEXT_PAGE(empty_zero_page)
        .skip PAGE_SIZE
 
-#ifdef CONFIG_KASAN
-/*
- * This page used as early shadow. We don't use empty_zero_page
- * at early stages, stack instrumentation could write some garbage
- * to this page.
- * Latter we reuse it as zero shadow for large ranges of memory
- * that allowed to access, but not instrumented by kasan
- * (vmalloc/vmemmap ...).
- */
-NEXT_PAGE(kasan_zero_page)
-       .skip PAGE_SIZE
-#endif
index 88b366487b0e44b613e83d412febfad74381ca92..c7dfe1be784e2c6ef672c14454d24102f24b18e9 100644 (file)
@@ -347,14 +347,22 @@ int check_irq_vectors_for_cpu_disable(void)
                        if (!desc)
                                continue;
 
+                       /*
+                        * Protect against concurrent action removal,
+                        * affinity changes etc.
+                        */
+                       raw_spin_lock(&desc->lock);
                        data = irq_desc_get_irq_data(desc);
                        cpumask_copy(&affinity_new, data->affinity);
                        cpumask_clear_cpu(this_cpu, &affinity_new);
 
                        /* Do not count inactive or per-cpu irqs. */
-                       if (!irq_has_action(irq) || irqd_is_per_cpu(data))
+                       if (!irq_has_action(irq) || irqd_is_per_cpu(data)) {
+                               raw_spin_unlock(&desc->lock);
                                continue;
+                       }
 
+                       raw_spin_unlock(&desc->lock);
                        /*
                         * A single irq may be mapped to multiple
                         * cpu's vector_irq[] (for example IOAPIC cluster
@@ -385,6 +393,9 @@ int check_irq_vectors_for_cpu_disable(void)
                 * vector. If the vector is marked in the used vectors
                 * bitmap or an irq is assigned to it, we don't count
                 * it as available.
+                *
+                * As this is an inaccurate snapshot anyway, we can do
+                * this w/o holding vector_lock.
                 */
                for (vector = FIRST_EXTERNAL_VECTOR;
                     vector < first_system_vector; vector++) {
@@ -486,6 +497,11 @@ void fixup_irqs(void)
         */
        mdelay(1);
 
+       /*
+        * We can walk the vector array of this cpu without holding
+        * vector_lock because the cpu is already marked !online, so
+        * nothing else will touch it.
+        */
        for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
                unsigned int irr;
 
@@ -497,9 +513,9 @@ void fixup_irqs(void)
                        irq = __this_cpu_read(vector_irq[vector]);
 
                        desc = irq_to_desc(irq);
+                       raw_spin_lock(&desc->lock);
                        data = irq_desc_get_irq_data(desc);
                        chip = irq_data_get_irq_chip(data);
-                       raw_spin_lock(&desc->lock);
                        if (chip->irq_retrigger) {
                                chip->irq_retrigger(data);
                                __this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED);
index c37886d759ccac2736c36b357cc0f399786f2fb3..2bcc0525f1c10e80b3db33df075b3189c4a68239 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
 
 #include <asm/mmu_context.h>
 #include <asm/syscalls.h>
 
-#ifdef CONFIG_SMP
+/* context.lock is held for us, so we don't need any locking. */
 static void flush_ldt(void *current_mm)
 {
-       if (current->active_mm == current_mm)
-               load_LDT(&current->active_mm->context);
+       mm_context_t *pc;
+
+       if (current->active_mm != current_mm)
+               return;
+
+       pc = &current->active_mm->context;
+       set_ldt(pc->ldt->entries, pc->ldt->size);
 }
-#endif
 
-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
+/* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
+static struct ldt_struct *alloc_ldt_struct(int size)
 {
-       void *oldldt, *newldt;
-       int oldsize;
-
-       if (mincount <= pc->size)
-               return 0;
-       oldsize = pc->size;
-       mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) &
-                       (~(PAGE_SIZE / LDT_ENTRY_SIZE - 1));
-       if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE)
-               newldt = vmalloc(mincount * LDT_ENTRY_SIZE);
+       struct ldt_struct *new_ldt;
+       int alloc_size;
+
+       if (size > LDT_ENTRIES)
+               return NULL;
+
+       new_ldt = kmalloc(sizeof(struct ldt_struct), GFP_KERNEL);
+       if (!new_ldt)
+               return NULL;
+
+       BUILD_BUG_ON(LDT_ENTRY_SIZE != sizeof(struct desc_struct));
+       alloc_size = size * LDT_ENTRY_SIZE;
+
+       /*
+        * Xen is very picky: it requires a page-aligned LDT that has no
+        * trailing nonzero bytes in any page that contains LDT descriptors.
+        * Keep it simple: zero the whole allocation and never allocate less
+        * than PAGE_SIZE.
+        */
+       if (alloc_size > PAGE_SIZE)
+               new_ldt->entries = vzalloc(alloc_size);
        else
-               newldt = (void *)__get_free_page(GFP_KERNEL);
-
-       if (!newldt)
-               return -ENOMEM;
+               new_ldt->entries = kzalloc(PAGE_SIZE, GFP_KERNEL);
 
-       if (oldsize)
-               memcpy(newldt, pc->ldt, oldsize * LDT_ENTRY_SIZE);
-       oldldt = pc->ldt;
-       memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
-              (mincount - oldsize) * LDT_ENTRY_SIZE);
+       if (!new_ldt->entries) {
+               kfree(new_ldt);
+               return NULL;
+       }
 
-       paravirt_alloc_ldt(newldt, mincount);
+       new_ldt->size = size;
+       return new_ldt;
+}
 
-#ifdef CONFIG_X86_64
-       /* CHECKME: Do we really need this ? */
-       wmb();
-#endif
-       pc->ldt = newldt;
-       wmb();
-       pc->size = mincount;
-       wmb();
-
-       if (reload) {
-#ifdef CONFIG_SMP
-               preempt_disable();
-               load_LDT(pc);
-               if (!cpumask_equal(mm_cpumask(current->mm),
-                                  cpumask_of(smp_processor_id())))
-                       smp_call_function(flush_ldt, current->mm, 1);
-               preempt_enable();
-#else
-               load_LDT(pc);
-#endif
-       }
-       if (oldsize) {
-               paravirt_free_ldt(oldldt, oldsize);
-               if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
-                       vfree(oldldt);
-               else
-                       put_page(virt_to_page(oldldt));
-       }
-       return 0;
+/* After calling this, the LDT is immutable. */
+static void finalize_ldt_struct(struct ldt_struct *ldt)
+{
+       paravirt_alloc_ldt(ldt->entries, ldt->size);
 }
 
-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
+/* context.lock is held */
+static void install_ldt(struct mm_struct *current_mm,
+                       struct ldt_struct *ldt)
 {
-       int err = alloc_ldt(new, old->size, 0);
-       int i;
+       /* Synchronizes with lockless_dereference in load_mm_ldt. */
+       smp_store_release(&current_mm->context.ldt, ldt);
+
+       /* Activate the LDT for all CPUs using current_mm. */
+       on_each_cpu_mask(mm_cpumask(current_mm), flush_ldt, current_mm, true);
+}
 
-       if (err < 0)
-               return err;
+static void free_ldt_struct(struct ldt_struct *ldt)
+{
+       if (likely(!ldt))
+               return;
 
-       for (i = 0; i < old->size; i++)
-               write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
-       return 0;
+       paravirt_free_ldt(ldt->entries, ldt->size);
+       if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE)
+               vfree(ldt->entries);
+       else
+               kfree(ldt->entries);
+       kfree(ldt);
 }
 
 /*
@@ -104,17 +105,37 @@ static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
  */
 int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
+       struct ldt_struct *new_ldt;
        struct mm_struct *old_mm;
        int retval = 0;
 
        mutex_init(&mm->context.lock);
-       mm->context.size = 0;
        old_mm = current->mm;
-       if (old_mm && old_mm->context.size > 0) {
-               mutex_lock(&old_mm->context.lock);
-               retval = copy_ldt(&mm->context, &old_mm->context);
-               mutex_unlock(&old_mm->context.lock);
+       if (!old_mm) {
+               mm->context.ldt = NULL;
+               return 0;
        }
+
+       mutex_lock(&old_mm->context.lock);
+       if (!old_mm->context.ldt) {
+               mm->context.ldt = NULL;
+               goto out_unlock;
+       }
+
+       new_ldt = alloc_ldt_struct(old_mm->context.ldt->size);
+       if (!new_ldt) {
+               retval = -ENOMEM;
+               goto out_unlock;
+       }
+
+       memcpy(new_ldt->entries, old_mm->context.ldt->entries,
+              new_ldt->size * LDT_ENTRY_SIZE);
+       finalize_ldt_struct(new_ldt);
+
+       mm->context.ldt = new_ldt;
+
+out_unlock:
+       mutex_unlock(&old_mm->context.lock);
        return retval;
 }
 
@@ -125,53 +146,47 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
  */
 void destroy_context(struct mm_struct *mm)
 {
-       if (mm->context.size) {
-#ifdef CONFIG_X86_32
-               /* CHECKME: Can this ever happen ? */
-               if (mm == current->active_mm)
-                       clear_LDT();
-#endif
-               paravirt_free_ldt(mm->context.ldt, mm->context.size);
-               if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
-                       vfree(mm->context.ldt);
-               else
-                       put_page(virt_to_page(mm->context.ldt));
-               mm->context.size = 0;
-       }
+       free_ldt_struct(mm->context.ldt);
+       mm->context.ldt = NULL;
 }
 
 static int read_ldt(void __user *ptr, unsigned long bytecount)
 {
-       int err;
+       int retval;
        unsigned long size;
        struct mm_struct *mm = current->mm;
 
-       if (!mm->context.size)
-               return 0;
+       mutex_lock(&mm->context.lock);
+
+       if (!mm->context.ldt) {
+               retval = 0;
+               goto out_unlock;
+       }
+
        if (bytecount > LDT_ENTRY_SIZE * LDT_ENTRIES)
                bytecount = LDT_ENTRY_SIZE * LDT_ENTRIES;
 
-       mutex_lock(&mm->context.lock);
-       size = mm->context.size * LDT_ENTRY_SIZE;
+       size = mm->context.ldt->size * LDT_ENTRY_SIZE;
        if (size > bytecount)
                size = bytecount;
 
-       err = 0;
-       if (copy_to_user(ptr, mm->context.ldt, size))
-               err = -EFAULT;
-       mutex_unlock(&mm->context.lock);
-       if (err < 0)
-               goto error_return;
+       if (copy_to_user(ptr, mm->context.ldt->entries, size)) {
+               retval = -EFAULT;
+               goto out_unlock;
+       }
+
        if (size != bytecount) {
-               /* zero-fill the rest */
-               if (clear_user(ptr + size, bytecount - size) != 0) {
-                       err = -EFAULT;
-                       goto error_return;
+               /* Zero-fill the rest and pretend we read bytecount bytes. */
+               if (clear_user(ptr + size, bytecount - size)) {
+                       retval = -EFAULT;
+                       goto out_unlock;
                }
        }
-       return bytecount;
-error_return:
-       return err;
+       retval = bytecount;
+
+out_unlock:
+       mutex_unlock(&mm->context.lock);
+       return retval;
 }
 
 static int read_default_ldt(void __user *ptr, unsigned long bytecount)
@@ -195,6 +210,8 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
        struct desc_struct ldt;
        int error;
        struct user_desc ldt_info;
+       int oldsize, newsize;
+       struct ldt_struct *new_ldt, *old_ldt;
 
        error = -EINVAL;
        if (bytecount != sizeof(ldt_info))
@@ -213,34 +230,39 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
                        goto out;
        }
 
-       mutex_lock(&mm->context.lock);
-       if (ldt_info.entry_number >= mm->context.size) {
-               error = alloc_ldt(&current->mm->context,
-                                 ldt_info.entry_number + 1, 1);
-               if (error < 0)
-                       goto out_unlock;
-       }
-
-       /* Allow LDTs to be cleared by the user. */
-       if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
-               if (oldmode || LDT_empty(&ldt_info)) {
-                       memset(&ldt, 0, sizeof(ldt));
-                       goto install;
+       if ((oldmode && !ldt_info.base_addr && !ldt_info.limit) ||
+           LDT_empty(&ldt_info)) {
+               /* The user wants to clear the entry. */
+               memset(&ldt, 0, sizeof(ldt));
+       } else {
+               if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
+                       error = -EINVAL;
+                       goto out;
                }
+
+               fill_ldt(&ldt, &ldt_info);
+               if (oldmode)
+                       ldt.avl = 0;
        }
 
-       if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
-               error = -EINVAL;
+       mutex_lock(&mm->context.lock);
+
+       old_ldt = mm->context.ldt;
+       oldsize = old_ldt ? old_ldt->size : 0;
+       newsize = max((int)(ldt_info.entry_number + 1), oldsize);
+
+       error = -ENOMEM;
+       new_ldt = alloc_ldt_struct(newsize);
+       if (!new_ldt)
                goto out_unlock;
-       }
 
-       fill_ldt(&ldt, &ldt_info);
-       if (oldmode)
-               ldt.avl = 0;
+       if (old_ldt)
+               memcpy(new_ldt->entries, old_ldt->entries, oldsize * LDT_ENTRY_SIZE);
+       new_ldt->entries[ldt_info.entry_number] = ldt;
+       finalize_ldt_struct(new_ldt);
 
-       /* Install the new entry ...  */
-install:
-       write_ldt_entry(mm->context.ldt, ldt_info.entry_number, &ldt);
+       install_ldt(mm, new_ldt);
+       free_ldt_struct(old_ldt);
        error = 0;
 
 out_unlock:
index c3e985d1751ced9dbab5ac0aa7c38f9623b449f4..d05bd2e2ee91e642b0162a00021043e79d3b4b3a 100644 (file)
@@ -408,15 +408,15 @@ static void default_do_nmi(struct pt_regs *regs)
 NOKPROBE_SYMBOL(default_do_nmi);
 
 /*
- * NMIs can hit breakpoints which will cause it to lose its
- * NMI context with the CPU when the breakpoint does an iret.
- */
-#ifdef CONFIG_X86_32
-/*
- * For i386, NMIs use the same stack as the kernel, and we can
- * add a workaround to the iret problem in C (preventing nested
- * NMIs if an NMI takes a trap). Simply have 3 states the NMI
- * can be in:
+ * NMIs can page fault or hit breakpoints which will cause it to lose
+ * its NMI context with the CPU when the breakpoint or page fault does an IRET.
+ *
+ * As a result, NMIs can nest if NMIs get unmasked due an IRET during
+ * NMI processing.  On x86_64, the asm glue protects us from nested NMIs
+ * if the outer NMI came from kernel mode, but we can still nest if the
+ * outer NMI came from user mode.
+ *
+ * To handle these nested NMIs, we have three states:
  *
  *  1) not running
  *  2) executing
@@ -430,15 +430,14 @@ NOKPROBE_SYMBOL(default_do_nmi);
  * (Note, the latch is binary, thus multiple NMIs triggering,
  *  when one is running, are ignored. Only one NMI is restarted.)
  *
- * If an NMI hits a breakpoint that executes an iret, another
- * NMI can preempt it. We do not want to allow this new NMI
- * to run, but we want to execute it when the first one finishes.
- * We set the state to "latched", and the exit of the first NMI will
- * perform a dec_return, if the result is zero (NOT_RUNNING), then
- * it will simply exit the NMI handler. If not, the dec_return
- * would have set the state to NMI_EXECUTING (what we want it to
- * be when we are running). In this case, we simply jump back
- * to rerun the NMI handler again, and restart the 'latched' NMI.
+ * If an NMI executes an iret, another NMI can preempt it. We do not
+ * want to allow this new NMI to run, but we want to execute it when the
+ * first one finishes.  We set the state to "latched", and the exit of
+ * the first NMI will perform a dec_return, if the result is zero
+ * (NOT_RUNNING), then it will simply exit the NMI handler. If not, the
+ * dec_return would have set the state to NMI_EXECUTING (what we want it
+ * to be when we are running). In this case, we simply jump back to
+ * rerun the NMI handler again, and restart the 'latched' NMI.
  *
  * No trap (breakpoint or page fault) should be hit before nmi_restart,
  * thus there is no race between the first check of state for NOT_RUNNING
@@ -461,49 +460,36 @@ enum nmi_states {
 static DEFINE_PER_CPU(enum nmi_states, nmi_state);
 static DEFINE_PER_CPU(unsigned long, nmi_cr2);
 
-#define nmi_nesting_preprocess(regs)                                   \
-       do {                                                            \
-               if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {      \
-                       this_cpu_write(nmi_state, NMI_LATCHED);         \
-                       return;                                         \
-               }                                                       \
-               this_cpu_write(nmi_state, NMI_EXECUTING);               \
-               this_cpu_write(nmi_cr2, read_cr2());                    \
-       } while (0);                                                    \
-       nmi_restart:
-
-#define nmi_nesting_postprocess()                                      \
-       do {                                                            \
-               if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))     \
-                       write_cr2(this_cpu_read(nmi_cr2));              \
-               if (this_cpu_dec_return(nmi_state))                     \
-                       goto nmi_restart;                               \
-       } while (0)
-#else /* x86_64 */
+#ifdef CONFIG_X86_64
 /*
- * In x86_64 things are a bit more difficult. This has the same problem
- * where an NMI hitting a breakpoint that calls iret will remove the
- * NMI context, allowing a nested NMI to enter. What makes this more
- * difficult is that both NMIs and breakpoints have their own stack.
- * When a new NMI or breakpoint is executed, the stack is set to a fixed
- * point. If an NMI is nested, it will have its stack set at that same
- * fixed address that the first NMI had, and will start corrupting the
- * stack. This is handled in entry_64.S, but the same problem exists with
- * the breakpoint stack.
+ * In x86_64, we need to handle breakpoint -> NMI -> breakpoint.  Without
+ * some care, the inner breakpoint will clobber the outer breakpoint's
+ * stack.
  *
- * If a breakpoint is being processed, and the debug stack is being used,
- * if an NMI comes in and also hits a breakpoint, the stack pointer
- * will be set to the same fixed address as the breakpoint that was
- * interrupted, causing that stack to be corrupted. To handle this case,
- * check if the stack that was interrupted is the debug stack, and if
- * so, change the IDT so that new breakpoints will use the current stack
- * and not switch to the fixed address. On return of the NMI, switch back
- * to the original IDT.
+ * If a breakpoint is being processed, and the debug stack is being
+ * used, if an NMI comes in and also hits a breakpoint, the stack
+ * pointer will be set to the same fixed address as the breakpoint that
+ * was interrupted, causing that stack to be corrupted. To handle this
+ * case, check if the stack that was interrupted is the debug stack, and
+ * if so, change the IDT so that new breakpoints will use the current
+ * stack and not switch to the fixed address. On return of the NMI,
+ * switch back to the original IDT.
  */
 static DEFINE_PER_CPU(int, update_debug_stack);
+#endif
 
-static inline void nmi_nesting_preprocess(struct pt_regs *regs)
+dotraplinkage notrace void
+do_nmi(struct pt_regs *regs, long error_code)
 {
+       if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {
+               this_cpu_write(nmi_state, NMI_LATCHED);
+               return;
+       }
+       this_cpu_write(nmi_state, NMI_EXECUTING);
+       this_cpu_write(nmi_cr2, read_cr2());
+nmi_restart:
+
+#ifdef CONFIG_X86_64
        /*
         * If we interrupted a breakpoint, it is possible that
         * the nmi handler will have breakpoints too. We need to
@@ -514,22 +500,8 @@ static inline void nmi_nesting_preprocess(struct pt_regs *regs)
                debug_stack_set_zero();
                this_cpu_write(update_debug_stack, 1);
        }
-}
-
-static inline void nmi_nesting_postprocess(void)
-{
-       if (unlikely(this_cpu_read(update_debug_stack))) {
-               debug_stack_reset();
-               this_cpu_write(update_debug_stack, 0);
-       }
-}
 #endif
 
-dotraplinkage notrace void
-do_nmi(struct pt_regs *regs, long error_code)
-{
-       nmi_nesting_preprocess(regs);
-
        nmi_enter();
 
        inc_irq_stat(__nmi_count);
@@ -539,8 +511,17 @@ do_nmi(struct pt_regs *regs, long error_code)
 
        nmi_exit();
 
-       /* On i386, may loop back to preprocess */
-       nmi_nesting_postprocess();
+#ifdef CONFIG_X86_64
+       if (unlikely(this_cpu_read(update_debug_stack))) {
+               debug_stack_reset();
+               this_cpu_write(update_debug_stack, 0);
+       }
+#endif
+
+       if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
+               write_cr2(this_cpu_read(nmi_cr2));
+       if (this_cpu_dec_return(nmi_state))
+               goto nmi_restart;
 }
 NOKPROBE_SYMBOL(do_nmi);
 
index 9cad694ed7c4d6a755b34af705e0a055cb0c04aa..c27cad7267655c3794972344adf0b7924e38c138 100644 (file)
@@ -81,7 +81,7 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister);
  */
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-       *dst = *src;
+       memcpy(dst, src, arch_task_struct_size);
 
        return fpu__copy(&dst->thread.fpu, &src->thread.fpu);
 }
@@ -408,6 +408,7 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
 static void mwait_idle(void)
 {
        if (!current_set_polling_and_test()) {
+               trace_cpu_idle_rcuidle(1, smp_processor_id());
                if (this_cpu_has(X86_BUG_CLFLUSH_MONITOR)) {
                        smp_mb(); /* quirk */
                        clflush((void *)&current_thread_info()->flags);
@@ -419,6 +420,7 @@ static void mwait_idle(void)
                        __sti_mwait(0, 0);
                else
                        local_irq_enable();
+               trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
        } else {
                local_irq_enable();
        }
index 71d7849a07f7ca93b126bf081464012c7a91c9a6..f6b916387590158706b8ef4ec68bfef64702ff0f 100644 (file)
@@ -121,11 +121,11 @@ void __show_regs(struct pt_regs *regs, int all)
 void release_thread(struct task_struct *dead_task)
 {
        if (dead_task->mm) {
-               if (dead_task->mm->context.size) {
+               if (dead_task->mm->context.ldt) {
                        pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
                                dead_task->comm,
                                dead_task->mm->context.ldt,
-                               dead_task->mm->context.size);
+                               dead_task->mm->context.ldt->size);
                        BUG();
                }
        }
index 206996c1669db344aba7ff072f734552723e7938..71820c42b6ce6bc1020bbc44277967d7e23f011e 100644 (file)
@@ -93,8 +93,15 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
                COPY(r15);
 #endif /* CONFIG_X86_64 */
 
+#ifdef CONFIG_X86_32
                COPY_SEG_CPL3(cs);
                COPY_SEG_CPL3(ss);
+#else /* !CONFIG_X86_32 */
+               /* Kernel saves and restores only the CS segment register on signals,
+                * which is the bare minimum needed to allow mixed 32/64-bit code.
+                * App's signal handler can save/restore other segments if needed. */
+               COPY_SEG_CPL3(cs);
+#endif /* CONFIG_X86_32 */
 
                get_user_ex(tmpflags, &sc->flags);
                regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
@@ -154,9 +161,8 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
 #else /* !CONFIG_X86_32 */
                put_user_ex(regs->flags, &sc->flags);
                put_user_ex(regs->cs, &sc->cs);
-               put_user_ex(0, &sc->__pad2);
-               put_user_ex(0, &sc->__pad1);
-               put_user_ex(regs->ss, &sc->ss);
+               put_user_ex(0, &sc->gs);
+               put_user_ex(0, &sc->fs);
 #endif /* CONFIG_X86_32 */
 
                put_user_ex(fpstate, &sc->fpstate);
@@ -451,19 +457,9 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig,
 
        regs->sp = (unsigned long)frame;
 
-       /*
-        * Set up the CS and SS registers to run signal handlers in
-        * 64-bit mode, even if the handler happens to be interrupting
-        * 32-bit or 16-bit code.
-        *
-        * SS is subtle.  In 64-bit mode, we don't need any particular
-        * SS descriptor, but we do need SS to be valid.  It's possible
-        * that the old SS is entirely bogus -- this can happen if the
-        * signal we're trying to deliver is #GP or #SS caused by a bad
-        * SS value.
-        */
+       /* Set up the CS register to run signal handlers in 64-bit mode,
+          even if the handler happens to be interrupting 32-bit code. */
        regs->cs = __USER_CS;
-       regs->ss = __USER_DS;
 
        return 0;
 }
index 8add66b22f333cbc5e8936b41e64525b7f49e1bc..b1f3ed9c7a9efcb1df4ef0da09a731600cbeb679 100644 (file)
@@ -170,11 +170,6 @@ static void smp_callin(void)
         */
        apic_ap_setup();
 
-       /*
-        * Need to setup vector mappings before we enable interrupts.
-        */
-       setup_vector_irq(smp_processor_id());
-
        /*
         * Save our processor parameters. Note: this information
         * is needed for clock calibration.
@@ -239,18 +234,13 @@ static void notrace start_secondary(void *unused)
        check_tsc_sync_target();
 
        /*
-        * Enable the espfix hack for this CPU
-        */
-#ifdef CONFIG_X86_ESPFIX64
-       init_espfix_ap();
-#endif
-
-       /*
-        * We need to hold vector_lock so there the set of online cpus
-        * does not change while we are assigning vectors to cpus.  Holding
-        * this lock ensures we don't half assign or remove an irq from a cpu.
+        * Lock vector_lock and initialize the vectors on this cpu
+        * before setting the cpu online. We must set it online with
+        * vector_lock held to prevent a concurrent setup/teardown
+        * from seeing a half valid vector space.
         */
        lock_vector_lock();
+       setup_vector_irq(smp_processor_id());
        set_cpu_online(smp_processor_id(), true);
        unlock_vector_lock();
        cpu_set_state_online(smp_processor_id());
@@ -854,6 +844,13 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
        initial_code = (unsigned long)start_secondary;
        stack_start  = idle->thread.sp;
 
+       /*
+        * Enable the espfix hack for this CPU
+       */
+#ifdef CONFIG_X86_ESPFIX64
+       init_espfix_ap(cpu);
+#endif
+
        /* So we see what's up */
        announce_cpu(cpu, apicid);
 
@@ -995,8 +992,17 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)
 
        common_cpu_up(cpu, tidle);
 
+       /*
+        * We have to walk the irq descriptors to setup the vector
+        * space for the cpu which comes online.  Prevent irq
+        * alloc/free across the bringup.
+        */
+       irq_lock_sparse();
+
        err = do_boot_cpu(apicid, cpu, tidle);
+
        if (err) {
+               irq_unlock_sparse();
                pr_err("do_boot_cpu failed(%d) to wakeup CPU#%u\n", err, cpu);
                return -EIO;
        }
@@ -1014,6 +1020,8 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)
                touch_nmi_watchdog();
        }
 
+       irq_unlock_sparse();
+
        return 0;
 }
 
index 9b4d51d0c0d013274f7ba46c2e58319f0d1d9145..0ccb53a9fcd9361b83c7acd26e1f64601816a3d1 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 #include <linux/ptrace.h>
 #include <asm/desc.h>
+#include <asm/mmu_context.h>
 
 unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs)
 {
@@ -27,13 +28,14 @@ unsigned long convert_ip_to_linear(struct task_struct *child, struct pt_regs *re
                struct desc_struct *desc;
                unsigned long base;
 
-               seg &= ~7UL;
+               seg >>= 3;
 
                mutex_lock(&child->mm->context.lock);
-               if (unlikely((seg >> 3) >= child->mm->context.size))
+               if (unlikely(!child->mm->context.ldt ||
+                            seg >= child->mm->context.ldt->size))
                        addr = -1L; /* bogus selector, access would fault */
                else {
-                       desc = child->mm->context.ldt + seg;
+                       desc = &child->mm->context.ldt->entries[seg];
                        base = get_desc_base(desc);
 
                        /* 16-bit code segment? */
index 505449700e0cf4e66ea6284135482ac172fe756a..7437b41f6a47c290e0f26b8933b45e469235ccc4 100644 (file)
@@ -598,10 +598,19 @@ static unsigned long quick_pit_calibrate(void)
                        if (!pit_expect_msb(0xff-i, &delta, &d2))
                                break;
 
+                       delta -= tsc;
+
+                       /*
+                        * Extrapolate the error and fail fast if the error will
+                        * never be below 500 ppm.
+                        */
+                       if (i == 1 &&
+                           d1 + d2 >= (delta * MAX_QUICK_PIT_ITERATIONS) >> 11)
+                               return 0;
+
                        /*
                         * Iterate until the error is less than 500 ppm
                         */
-                       delta -= tsc;
                        if (d1+d2 >= delta >> 11)
                                continue;
 
index 64dd467930997adbfa6aecd25641ef2004c5488c..2fbea2544f2437bc0ae50ef00288dc320effd81e 100644 (file)
@@ -98,6 +98,8 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
                best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
 
        vcpu->arch.eager_fpu = use_eager_fpu() || guest_cpuid_has_mpx(vcpu);
+       if (vcpu->arch.eager_fpu)
+               kvm_x86_ops->fpu_activate(vcpu);
 
        /*
         * The existing code assumes virtual address is 48-bit in the canonical
index 7dbced309ddb526d99ae41114bf3afd8488ccaa8..5c520ebf6343270272679e213b19cd9380b63293 100644 (file)
@@ -200,6 +200,7 @@ int kvm_assign_device(struct kvm *kvm, struct pci_dev *pdev)
                        goto out_unmap;
        }
 
+       kvm_arch_start_assignment(kvm);
        pci_set_dev_assigned(pdev);
 
        dev_info(&pdev->dev, "kvm assign device\n");
@@ -224,6 +225,7 @@ int kvm_deassign_device(struct kvm *kvm, struct pci_dev *pdev)
        iommu_detach_device(domain, &pdev->dev);
 
        pci_clear_dev_assigned(pdev);
+       kvm_arch_end_assignment(kvm);
 
        dev_info(&pdev->dev, "kvm deassign device\n");
 
index 954e98a8c2e38bf9861d4d6349eb721264e8cb18..2a5ca97c263bb48092ea80f88c7d30120ea63b6e 100644 (file)
@@ -1595,7 +1595,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
        for (i = 0; i < APIC_LVT_NUM; i++)
                apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
        apic_update_lvtt(apic);
-       if (!(vcpu->kvm->arch.disabled_quirks & KVM_QUIRK_LINT0_REENABLED))
+       if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED))
                apic_set_reg(apic, APIC_LVT0,
                             SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
        apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0));
index f807496b62c2cc76e82a60cd58ee187f0cdc77c2..44171462bd2a31561645aff21c83584b82eed6ff 100644 (file)
@@ -2479,6 +2479,14 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
        return 0;
 }
 
+static bool kvm_is_mmio_pfn(pfn_t pfn)
+{
+       if (pfn_valid(pfn))
+               return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn));
+
+       return true;
+}
+
 static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                    unsigned pte_access, int level,
                    gfn_t gfn, pfn_t pfn, bool speculative,
@@ -2506,7 +2514,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                spte |= PT_PAGE_SIZE_MASK;
        if (tdp_enabled)
                spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn,
-                       kvm_is_reserved_pfn(pfn));
+                       kvm_is_mmio_pfn(pfn));
 
        if (host_writable)
                spte |= SPTE_HOST_WRITEABLE;
index de1d2d8062e24048232af909d684f0c2ed9e21bc..9e8bf13572e6dc3f95d33d24f079d63e256a3a7a 100644 (file)
@@ -120,6 +120,16 @@ static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
        return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
 }
 
+static u8 mtrr_disabled_type(void)
+{
+       /*
+        * Intel SDM 11.11.2.2: all MTRRs are disabled when
+        * IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC
+        * memory type is applied to all of physical memory.
+        */
+       return MTRR_TYPE_UNCACHABLE;
+}
+
 /*
 * Three terms are used in the following code:
 * - segment, it indicates the address segments covered by fixed MTRRs.
@@ -434,6 +444,8 @@ struct mtrr_iter {
 
        /* output fields. */
        int mem_type;
+       /* mtrr is completely disabled? */
+       bool mtrr_disabled;
        /* [start, end) is not fully covered in MTRRs? */
        bool partial_map;
 
@@ -549,7 +561,7 @@ static void mtrr_lookup_var_next(struct mtrr_iter *iter)
 static void mtrr_lookup_start(struct mtrr_iter *iter)
 {
        if (!mtrr_is_enabled(iter->mtrr_state)) {
-               iter->partial_map = true;
+               iter->mtrr_disabled = true;
                return;
        }
 
@@ -563,6 +575,7 @@ static void mtrr_lookup_init(struct mtrr_iter *iter,
        iter->mtrr_state = mtrr_state;
        iter->start = start;
        iter->end = end;
+       iter->mtrr_disabled = false;
        iter->partial_map = false;
        iter->fixed = false;
        iter->range = NULL;
@@ -656,15 +669,19 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
                return MTRR_TYPE_WRBACK;
        }
 
-       /* It is not covered by MTRRs. */
-       if (iter.partial_map) {
-               /*
-                * We just check one page, partially covered by MTRRs is
-                * impossible.
-                */
-               WARN_ON(type != -1);
-               type = mtrr_default_type(mtrr_state);
-       }
+       if (iter.mtrr_disabled)
+               return mtrr_disabled_type();
+
+       /* not contained in any MTRRs. */
+       if (type == -1)
+               return mtrr_default_type(mtrr_state);
+
+       /*
+        * We just check one page, partially covered by MTRRs is
+        * impossible.
+        */
+       WARN_ON(iter.partial_map);
+
        return type;
 }
 EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
@@ -689,6 +706,9 @@ bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
                        return false;
        }
 
+       if (iter.mtrr_disabled)
+               return true;
+
        if (!iter.partial_map)
                return true;
 
index 602b974a60a626e18d11965ed5ad1461c329bee8..8e0c0844c6b9681e31e64bdeba0f1822108bec3e 100644 (file)
@@ -865,6 +865,64 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
        set_msr_interception(msrpm, MSR_IA32_LASTINTTOIP, 0, 0);
 }
 
+#define MTRR_TYPE_UC_MINUS     7
+#define MTRR2PROTVAL_INVALID 0xff
+
+static u8 mtrr2protval[8];
+
+static u8 fallback_mtrr_type(int mtrr)
+{
+       /*
+        * WT and WP aren't always available in the host PAT.  Treat
+        * them as UC and UC- respectively.  Everything else should be
+        * there.
+        */
+       switch (mtrr)
+       {
+       case MTRR_TYPE_WRTHROUGH:
+               return MTRR_TYPE_UNCACHABLE;
+       case MTRR_TYPE_WRPROT:
+               return MTRR_TYPE_UC_MINUS;
+       default:
+               BUG();
+       }
+}
+
+static void build_mtrr2protval(void)
+{
+       int i;
+       u64 pat;
+
+       for (i = 0; i < 8; i++)
+               mtrr2protval[i] = MTRR2PROTVAL_INVALID;
+
+       /* Ignore the invalid MTRR types.  */
+       mtrr2protval[2] = 0;
+       mtrr2protval[3] = 0;
+
+       /*
+        * Use host PAT value to figure out the mapping from guest MTRR
+        * values to nested page table PAT/PCD/PWT values.  We do not
+        * want to change the host PAT value every time we enter the
+        * guest.
+        */
+       rdmsrl(MSR_IA32_CR_PAT, pat);
+       for (i = 0; i < 8; i++) {
+               u8 mtrr = pat >> (8 * i);
+
+               if (mtrr2protval[mtrr] == MTRR2PROTVAL_INVALID)
+                       mtrr2protval[mtrr] = __cm_idx2pte(i);
+       }
+
+       for (i = 0; i < 8; i++) {
+               if (mtrr2protval[i] == MTRR2PROTVAL_INVALID) {
+                       u8 fallback = fallback_mtrr_type(i);
+                       mtrr2protval[i] = mtrr2protval[fallback];
+                       BUG_ON(mtrr2protval[i] == MTRR2PROTVAL_INVALID);
+               }
+       }
+}
+
 static __init int svm_hardware_setup(void)
 {
        int cpu;
@@ -931,6 +989,7 @@ static __init int svm_hardware_setup(void)
        } else
                kvm_disable_tdp();
 
+       build_mtrr2protval();
        return 0;
 
 err:
@@ -1085,6 +1144,39 @@ static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
        return target_tsc - tsc;
 }
 
+static void svm_set_guest_pat(struct vcpu_svm *svm, u64 *g_pat)
+{
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+
+       /* Unlike Intel, AMD takes the guest's CR0.CD into account.
+        *
+        * AMD does not have IPAT.  To emulate it for the case of guests
+        * with no assigned devices, just set everything to WB.  If guests
+        * have assigned devices, however, we cannot force WB for RAM
+        * pages only, so use the guest PAT directly.
+        */
+       if (!kvm_arch_has_assigned_device(vcpu->kvm))
+               *g_pat = 0x0606060606060606;
+       else
+               *g_pat = vcpu->arch.pat;
+}
+
+static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
+{
+       u8 mtrr;
+
+       /*
+        * 1. MMIO: trust guest MTRR, so same as item 3.
+        * 2. No passthrough: always map as WB, and force guest PAT to WB as well
+        * 3. Passthrough: can't guarantee the result, try to trust guest.
+        */
+       if (!is_mmio && !kvm_arch_has_assigned_device(vcpu->kvm))
+               return 0;
+
+       mtrr = kvm_mtrr_get_guest_memory_type(vcpu, gfn);
+       return mtrr2protval[mtrr];
+}
+
 static void init_vmcb(struct vcpu_svm *svm, bool init_event)
 {
        struct vmcb_control_area *control = &svm->vmcb->control;
@@ -1180,6 +1272,7 @@ static void init_vmcb(struct vcpu_svm *svm, bool init_event)
                clr_cr_intercept(svm, INTERCEPT_CR3_READ);
                clr_cr_intercept(svm, INTERCEPT_CR3_WRITE);
                save->g_pat = svm->vcpu.arch.pat;
+               svm_set_guest_pat(svm, &save->g_pat);
                save->cr3 = 0;
                save->cr4 = 0;
        }
@@ -1579,7 +1672,7 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
         * does not do it - this results in some delay at
         * reboot
         */
-       if (!(vcpu->kvm->arch.disabled_quirks & KVM_QUIRK_CD_NW_CLEARED))
+       if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED))
                cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
        svm->vmcb->save.cr0 = cr0;
        mark_dirty(svm->vmcb, VMCB_CR);
@@ -3254,6 +3347,16 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
        case MSR_VM_IGNNE:
                vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
                break;
+       case MSR_IA32_CR_PAT:
+               if (npt_enabled) {
+                       if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
+                               return 1;
+                       vcpu->arch.pat = data;
+                       svm_set_guest_pat(svm, &svm->vmcb->save.g_pat);
+                       mark_dirty(svm->vmcb, VMCB_NPT);
+                       break;
+               }
+               /* fall through */
        default:
                return kvm_set_msr_common(vcpu, msr);
        }
@@ -4088,11 +4191,6 @@ static bool svm_has_high_real_mode_segbase(void)
        return true;
 }
 
-static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
-{
-       return 0;
-}
-
 static void svm_cpuid_update(struct kvm_vcpu *vcpu)
 {
 }
index e856dd566f4c2a6c10a4a6dc9c6ea018fe72cdda..83b7b5cd75d52dd67976274da3c11807f1c35490 100644 (file)
@@ -8632,22 +8632,17 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
        u64 ipat = 0;
 
        /* For VT-d and EPT combination
-        * 1. MMIO: always map as UC
+        * 1. MMIO: guest may want to apply WC, trust it.
         * 2. EPT with VT-d:
         *   a. VT-d without snooping control feature: can't guarantee the
-        *      result, try to trust guest.
+        *      result, try to trust guest.  So the same as item 1.
         *   b. VT-d with snooping control feature: snooping control feature of
         *      VT-d engine can guarantee the cache correctness. Just set it
         *      to WB to keep consistent with host. So the same as item 3.
         * 3. EPT without VT-d: always map as WB and set IPAT=1 to keep
         *    consistent with host MTRR
         */
-       if (is_mmio) {
-               cache = MTRR_TYPE_UNCACHABLE;
-               goto exit;
-       }
-
-       if (!kvm_arch_has_noncoherent_dma(vcpu->kvm)) {
+       if (!is_mmio && !kvm_arch_has_noncoherent_dma(vcpu->kvm)) {
                ipat = VMX_EPT_IPAT_BIT;
                cache = MTRR_TYPE_WRBACK;
                goto exit;
@@ -8655,7 +8650,10 @@ static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 
        if (kvm_read_cr0(vcpu) & X86_CR0_CD) {
                ipat = VMX_EPT_IPAT_BIT;
-               cache = MTRR_TYPE_UNCACHABLE;
+               if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_CD_NW_CLEARED))
+                       cache = MTRR_TYPE_WRBACK;
+               else
+                       cache = MTRR_TYPE_UNCACHABLE;
                goto exit;
        }
 
index bbaf44e8f0d3cdd7100c40c98ccf2ab40ae1ea2f..8f0f6eca69da1dc6db95c16782871580bf57091d 100644 (file)
@@ -2105,7 +2105,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                if (guest_cpuid_has_tsc_adjust(vcpu)) {
                        if (!msr_info->host_initiated) {
                                s64 adj = data - vcpu->arch.ia32_tsc_adjust_msr;
-                               kvm_x86_ops->adjust_tsc_offset(vcpu, adj, true);
+                               adjust_tsc_offset_guest(vcpu, adj);
                        }
                        vcpu->arch.ia32_tsc_adjust_msr = data;
                }
@@ -3157,8 +3157,7 @@ static void load_xsave(struct kvm_vcpu *vcpu, u8 *src)
                        cpuid_count(XSTATE_CPUID, index,
                                    &size, &offset, &ecx, &edx);
                        memcpy(dest, src + offset, size);
-               } else
-                       WARN_ON_ONCE(1);
+               }
 
                valid -= feature;
        }
@@ -6328,6 +6327,7 @@ static void process_smi_save_state_64(struct kvm_vcpu *vcpu, char *buf)
 static void process_smi(struct kvm_vcpu *vcpu)
 {
        struct kvm_segment cs, ds;
+       struct desc_ptr dt;
        char buf[512];
        u32 cr0;
 
@@ -6360,6 +6360,10 @@ static void process_smi(struct kvm_vcpu *vcpu)
 
        kvm_x86_ops->set_cr4(vcpu, 0);
 
+       /* Undocumented: IDT limit is set to zero on entry to SMM.  */
+       dt.address = dt.size = 0;
+       kvm_x86_ops->set_idt(vcpu, &dt);
+
        __kvm_set_dr(vcpu, 7, DR7_FIXED_1);
 
        cs.selector = (vcpu->arch.smbase >> 4) & 0xffff;
@@ -7315,11 +7319,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 
        vcpu = kvm_x86_ops->vcpu_create(kvm, id);
 
-       /*
-        * Activate fpu unconditionally in case the guest needs eager FPU.  It will be
-        * deactivated soon if it doesn't.
-        */
-       kvm_x86_ops->fpu_activate(vcpu);
        return vcpu;
 }
 
@@ -8218,6 +8217,24 @@ bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu)
                        kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
+void kvm_arch_start_assignment(struct kvm *kvm)
+{
+       atomic_inc(&kvm->arch.assigned_device_count);
+}
+EXPORT_SYMBOL_GPL(kvm_arch_start_assignment);
+
+void kvm_arch_end_assignment(struct kvm *kvm)
+{
+       atomic_dec(&kvm->arch.assigned_device_count);
+}
+EXPORT_SYMBOL_GPL(kvm_arch_end_assignment);
+
+bool kvm_arch_has_assigned_device(struct kvm *kvm)
+{
+       return atomic_read(&kvm->arch.assigned_device_count);
+}
+EXPORT_SYMBOL_GPL(kvm_arch_has_assigned_device);
+
 void kvm_arch_register_noncoherent_dma(struct kvm *kvm)
 {
        atomic_inc(&kvm->arch.noncoherent_dma_count);
index edc8cdcd786b00627a1029c8bb3b2aedcb291d09..0ca2f3e4803c2a5846be297a51eb5c1cf67aff4a 100644 (file)
@@ -147,6 +147,11 @@ static inline void kvm_register_writel(struct kvm_vcpu *vcpu,
        return kvm_register_write(vcpu, reg, val);
 }
 
+static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
+{
+       return !(kvm->arch.disabled_quirks & quirk);
+}
+
 void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_set_pending_timer(struct kvm_vcpu *vcpu);
index ddf9ecb53cc3e23171ea889dc47339e67ba5d2c8..e342586db6e4b08230ce6a596c91e27bb5fcf2db 100644 (file)
@@ -20,7 +20,7 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
        unsigned long ret;
 
        if (__range_not_ok(from, n, TASK_SIZE))
-               return 0;
+               return n;
 
        /*
         * Even though this function is typically called from NMI/IRQ context
index f37e84ab49f38e335bde57880a6cbe8640fb2c4b..3d8f2e421466a8af255eba9602748fee8753a377 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/traps.h>
-#include <asm/desc.h>
 #include <asm/user.h>
 #include <asm/fpu/internal.h>
 
@@ -181,7 +180,7 @@ void math_emulate(struct math_emu_info *info)
                        math_abort(FPU_info, SIGILL);
                }
 
-               code_descriptor = LDT_DESCRIPTOR(FPU_CS);
+               code_descriptor = FPU_get_ldt_descriptor(FPU_CS);
                if (SEG_D_SIZE(code_descriptor)) {
                        /* The above test may be wrong, the book is not clear */
                        /* Segmented 32 bit protected mode */
index 9ccecb61a4fa129a82028b27edc18b91a2f99042..5e044d506b7aae8b17b2142966b11477cfe8e372 100644 (file)
 #include <linux/kernel.h>
 #include <linux/mm.h>
 
-/* s is always from a cpu register, and the cpu does bounds checking
- * during register load --> no further bounds checks needed */
-#define LDT_DESCRIPTOR(s)      (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
+#include <asm/desc.h>
+#include <asm/mmu_context.h>
+
+static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg)
+{
+       static struct desc_struct zero_desc;
+       struct desc_struct ret = zero_desc;
+
+#ifdef CONFIG_MODIFY_LDT_SYSCALL
+       seg >>= 3;
+       mutex_lock(&current->mm->context.lock);
+       if (current->mm->context.ldt && seg < current->mm->context.ldt->size)
+               ret = current->mm->context.ldt->entries[seg];
+       mutex_unlock(&current->mm->context.lock);
+#endif
+       return ret;
+}
+
 #define SEG_D_SIZE(x)          ((x).b & (3 << 21))
 #define SEG_G_BIT(x)           ((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)     (((x).b & (1 << 23)) ? 4096 : 1)
index 6ef5e99380f92134ba86a6a693b5ac6d3434e6d4..8300db71c2a62681006e137350961742190ec9dc 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/stddef.h>
 
 #include <asm/uaccess.h>
-#include <asm/desc.h>
 
 #include "fpu_system.h"
 #include "exception.h"
@@ -158,7 +157,7 @@ static long pm_address(u_char FPU_modrm, u_char segment,
                addr->selector = PM_REG_(segment);
        }
 
-       descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
+       descriptor = FPU_get_ldt_descriptor(addr->selector);
        base_address = SEG_BASE_ADDR(descriptor);
        address = base_address + offset;
        limit = base_address
index cc5ccc415cc01ef8ea9e58b3f81a281c9ab412bf..b9c78f3bcd6739718def393f49d1f1cbb0e8bb5c 100644 (file)
@@ -63,8 +63,6 @@ static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
                    !PageReserved(pfn_to_page(start_pfn + i)))
                        return 1;
 
-       WARN_ONCE(1, "ioremap on RAM pfn 0x%lx\n", start_pfn);
-
        return 0;
 }
 
@@ -94,7 +92,6 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        pgprot_t prot;
        int retval;
        void __iomem *ret_addr;
-       int ram_region;
 
        /* Don't allow wraparound or zero size */
        last_addr = phys_addr + size - 1;
@@ -117,23 +114,15 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
-       /* First check if whole region can be identified as RAM or not */
-       ram_region = region_is_ram(phys_addr, size);
-       if (ram_region > 0) {
-               WARN_ONCE(1, "ioremap on RAM at 0x%lx - 0x%lx\n",
-                               (unsigned long int)phys_addr,
-                               (unsigned long int)last_addr);
+       pfn      = phys_addr >> PAGE_SHIFT;
+       last_pfn = last_addr >> PAGE_SHIFT;
+       if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
+                                         __ioremap_check_ram) == 1) {
+               WARN_ONCE(1, "ioremap on RAM at %pa - %pa\n",
+                         &phys_addr, &last_addr);
                return NULL;
        }
 
-       /* If could not be identified(-1), check page by page */
-       if (ram_region < 0) {
-               pfn      = phys_addr >> PAGE_SHIFT;
-               last_pfn = last_addr >> PAGE_SHIFT;
-               if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
-                                         __ioremap_check_ram) == 1)
-                       return NULL;
-       }
        /*
         * Mappings have to be page-aligned
         */
index 4860906c6b9f8e751b39ad3d5d4874c6da92c2e3..e1840f3db5b583984e53bcc7d11787706dbbed26 100644 (file)
@@ -1,3 +1,4 @@
+#define pr_fmt(fmt) "kasan: " fmt
 #include <linux/bootmem.h>
 #include <linux/kasan.h>
 #include <linux/kdebug.h>
 extern pgd_t early_level4_pgt[PTRS_PER_PGD];
 extern struct range pfn_mapped[E820_X_MAX];
 
-extern unsigned char kasan_zero_page[PAGE_SIZE];
+static pud_t kasan_zero_pud[PTRS_PER_PUD] __page_aligned_bss;
+static pmd_t kasan_zero_pmd[PTRS_PER_PMD] __page_aligned_bss;
+static pte_t kasan_zero_pte[PTRS_PER_PTE] __page_aligned_bss;
+
+/*
+ * This page used as early shadow. We don't use empty_zero_page
+ * at early stages, stack instrumentation could write some garbage
+ * to this page.
+ * Latter we reuse it as zero shadow for large ranges of memory
+ * that allowed to access, but not instrumented by kasan
+ * (vmalloc/vmemmap ...).
+ */
+static unsigned char kasan_zero_page[PAGE_SIZE] __page_aligned_bss;
 
 static int __init map_range(struct range *range)
 {
@@ -36,7 +49,7 @@ static void __init clear_pgds(unsigned long start,
                pgd_clear(pgd_offset_k(start));
 }
 
-void __init kasan_map_early_shadow(pgd_t *pgd)
+static void __init kasan_map_early_shadow(pgd_t *pgd)
 {
        int i;
        unsigned long start = KASAN_SHADOW_START;
@@ -73,7 +86,7 @@ static int __init zero_pmd_populate(pud_t *pud, unsigned long addr,
        while (IS_ALIGNED(addr, PMD_SIZE) && addr + PMD_SIZE <= end) {
                WARN_ON(!pmd_none(*pmd));
                set_pmd(pmd, __pmd(__pa_nodebug(kasan_zero_pte)
-                                       | __PAGE_KERNEL_RO));
+                                       | _KERNPG_TABLE));
                addr += PMD_SIZE;
                pmd = pmd_offset(pud, addr);
        }
@@ -99,7 +112,7 @@ static int __init zero_pud_populate(pgd_t *pgd, unsigned long addr,
        while (IS_ALIGNED(addr, PUD_SIZE) && addr + PUD_SIZE <= end) {
                WARN_ON(!pud_none(*pud));
                set_pud(pud, __pud(__pa_nodebug(kasan_zero_pmd)
-                                       | __PAGE_KERNEL_RO));
+                                       | _KERNPG_TABLE));
                addr += PUD_SIZE;
                pud = pud_offset(pgd, addr);
        }
@@ -124,7 +137,7 @@ static int __init zero_pgd_populate(unsigned long addr, unsigned long end)
        while (IS_ALIGNED(addr, PGDIR_SIZE) && addr + PGDIR_SIZE <= end) {
                WARN_ON(!pgd_none(*pgd));
                set_pgd(pgd, __pgd(__pa_nodebug(kasan_zero_pud)
-                                       | __PAGE_KERNEL_RO));
+                                       | _KERNPG_TABLE));
                addr += PGDIR_SIZE;
                pgd = pgd_offset_k(addr);
        }
@@ -166,6 +179,26 @@ static struct notifier_block kasan_die_notifier = {
 };
 #endif
 
+void __init kasan_early_init(void)
+{
+       int i;
+       pteval_t pte_val = __pa_nodebug(kasan_zero_page) | __PAGE_KERNEL;
+       pmdval_t pmd_val = __pa_nodebug(kasan_zero_pte) | _KERNPG_TABLE;
+       pudval_t pud_val = __pa_nodebug(kasan_zero_pmd) | _KERNPG_TABLE;
+
+       for (i = 0; i < PTRS_PER_PTE; i++)
+               kasan_zero_pte[i] = __pte(pte_val);
+
+       for (i = 0; i < PTRS_PER_PMD; i++)
+               kasan_zero_pmd[i] = __pmd(pmd_val);
+
+       for (i = 0; i < PTRS_PER_PUD; i++)
+               kasan_zero_pud[i] = __pud(pud_val);
+
+       kasan_map_early_shadow(early_level4_pgt);
+       kasan_map_early_shadow(init_level4_pgt);
+}
+
 void __init kasan_init(void)
 {
        int i;
@@ -176,6 +209,7 @@ void __init kasan_init(void)
 
        memcpy(early_level4_pgt, init_level4_pgt, sizeof(early_level4_pgt));
        load_cr3(early_level4_pgt);
+       __flush_tlb_all();
 
        clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
@@ -202,5 +236,8 @@ void __init kasan_init(void)
        memset(kasan_zero_page, 0, PAGE_SIZE);
 
        load_cr3(init_level4_pgt);
+       __flush_tlb_all();
        init_task.kasan_depth = 0;
+
+       pr_info("Kernel address sanitizer initialized\n");
 }
index 9d518d693b4b7adf07463c695f3cd14412a19192..844b06d67df4da95cec611375d55c05d52884efd 100644 (file)
@@ -126,3 +126,10 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
                mm->get_unmapped_area = arch_get_unmapped_area_topdown;
        }
 }
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       if (vma->vm_flags & VM_MPX)
+               return "[mpx]";
+       return NULL;
+}
index 7a657f58bbea152057262a61e325c169f78bc516..db1b0bc5017c9f01b456a97b5b84d6d40a2c03b2 100644 (file)
 #define CREATE_TRACE_POINTS
 #include <asm/trace/mpx.h>
 
-static const char *mpx_mapping_name(struct vm_area_struct *vma)
-{
-       return "[mpx]";
-}
-
-static struct vm_operations_struct mpx_vma_ops = {
-       .name = mpx_mapping_name,
-};
-
-static int is_mpx_vma(struct vm_area_struct *vma)
-{
-       return (vma->vm_ops == &mpx_vma_ops);
-}
-
 static inline unsigned long mpx_bd_size_bytes(struct mm_struct *mm)
 {
        if (is_64bit_mm(mm))
@@ -53,9 +39,6 @@ static inline unsigned long mpx_bt_size_bytes(struct mm_struct *mm)
 /*
  * This is really a simplified "vm_mmap". it only handles MPX
  * bounds tables (the bounds directory is user-allocated).
- *
- * Later on, we use the vma->vm_ops to uniquely identify these
- * VMAs.
  */
 static unsigned long mpx_mmap(unsigned long len)
 {
@@ -101,7 +84,6 @@ static unsigned long mpx_mmap(unsigned long len)
                ret = -ENOMEM;
                goto out;
        }
-       vma->vm_ops = &mpx_vma_ops;
 
        if (vm_flags & VM_LOCKED) {
                up_write(&mm->mmap_sem);
@@ -812,7 +794,7 @@ static noinline int zap_bt_entries_mapping(struct mm_struct *mm,
                 * so stop immediately and return an error.  This
                 * probably results in a SIGSEGV.
                 */
-               if (!is_mpx_vma(vma))
+               if (!(vma->vm_flags & VM_MPX))
                        return -EINVAL;
 
                len = min(vma->vm_end, end) - addr;
@@ -945,9 +927,9 @@ static int try_unmap_single_bt(struct mm_struct *mm,
         * lots of tables even though we have no actual table
         * entries in use.
         */
-       while (next && is_mpx_vma(next))
+       while (next && (next->vm_flags & VM_MPX))
                next = next->vm_next;
-       while (prev && is_mpx_vma(prev))
+       while (prev && (prev->vm_flags & VM_MPX))
                prev = prev->vm_prev;
        /*
         * We know 'start' and 'end' lie within an area controlled
index 3250f2371aea5c9f2c8f8f19d4f6535627e0e188..90b924acd9822ffdd9409b9fd97325ea7954b97a 100644 (file)
@@ -117,7 +117,7 @@ static void flush_tlb_func(void *info)
                } else {
                        unsigned long addr;
                        unsigned long nr_pages =
-                               f->flush_end - f->flush_start / PAGE_SIZE;
+                               (f->flush_end - f->flush_start) / PAGE_SIZE;
                        addr = f->flush_start;
                        while (addr < f->flush_end) {
                                __flush_tlb_single(addr);
index 579a8fd74be07804d983a298641b755526f1cb44..be2e7a2b10d7169b39b0849703b305ebb52c8933 100644 (file)
@@ -269,7 +269,7 @@ static void emit_bpf_tail_call(u8 **pprog)
        EMIT4(0x48, 0x8B, 0x46,                   /* mov rax, qword ptr [rsi + 16] */
              offsetof(struct bpf_array, map.max_entries));
        EMIT3(0x48, 0x39, 0xD0);                  /* cmp rax, rdx */
-#define OFFSET1 44 /* number of bytes to jump */
+#define OFFSET1 47 /* number of bytes to jump */
        EMIT2(X86_JBE, OFFSET1);                  /* jbe out */
        label1 = cnt;
 
@@ -278,15 +278,15 @@ static void emit_bpf_tail_call(u8 **pprog)
         */
        EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */
        EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT);     /* cmp eax, MAX_TAIL_CALL_CNT */
-#define OFFSET2 33
+#define OFFSET2 36
        EMIT2(X86_JA, OFFSET2);                   /* ja out */
        label2 = cnt;
        EMIT3(0x83, 0xC0, 0x01);                  /* add eax, 1 */
        EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */
 
        /* prog = array->prog[index]; */
-       EMIT4(0x48, 0x8D, 0x44, 0xD6);            /* lea rax, [rsi + rdx * 8 + 0x50] */
-       EMIT1(offsetof(struct bpf_array, prog));
+       EMIT4_off32(0x48, 0x8D, 0x84, 0xD6,       /* lea rax, [rsi + rdx * 8 + offsetof(...)] */
+                   offsetof(struct bpf_array, prog));
        EMIT3(0x48, 0x8B, 0x00);                  /* mov rax, qword ptr [rax] */
 
        /* if (prog == NULL)
index cfba30f273921b302d03883be593d77d6a3f1fe7..e4308fe6afe81e4d8be5a42a6cc682174761fe1f 100644 (file)
@@ -972,6 +972,11 @@ u64 efi_mem_attributes(unsigned long phys_addr)
 
 static int __init arch_parse_efi_cmdline(char *str)
 {
+       if (!str) {
+               pr_warn("need at least one option\n");
+               return -EINVAL;
+       }
+
        if (parse_option_str(str, "old_map"))
                set_bit(EFI_OLD_MEMMAP, &efi.flags);
        if (parse_option_str(str, "debug"))
index 0d7dd1f5ac36fa6814c18522dd28561566c570eb..9ab52791fed59e3ab2e531611037c4ed9dc7bde3 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/fpu/internal.h>
 #include <asm/debugreg.h>
 #include <asm/cpu.h>
+#include <asm/mmu_context.h>
 
 #ifdef CONFIG_X86_32
 __visible unsigned long saved_context_ebx;
@@ -153,7 +154,7 @@ static void fix_processor_context(void)
        syscall_init();                         /* This sets MSR_*STAR and related */
 #endif
        load_TR_desc();                         /* This does ltr */
-       load_LDT(&current->active_mm->context); /* This does lldt */
+       load_mm_ldt(current->active_mm);        /* This does lldt */
 
        fpu__resume_cpu();
 }
index e88fda867a33b198bc356aded57d59f48fcfb4ee..484145368a241207d8aa80a5f758a7d0f3ef54cb 100644 (file)
@@ -8,7 +8,7 @@ config XEN
        select PARAVIRT_CLOCK
        select XEN_HAVE_PVMMU
        depends on X86_64 || (X86_32 && X86_PAE)
-       depends on X86_TSC
+       depends on X86_LOCAL_APIC && X86_TSC
        help
          This is the Linux Xen port.  Enabling this will allow the
          kernel to boot in a paravirtualized environment under the
@@ -17,7 +17,7 @@ config XEN
 config XEN_DOM0
        def_bool y
        depends on XEN && PCI_XEN && SWIOTLB_XEN
-       depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI
+       depends on X86_IO_APIC && ACPI && PCI
 
 config XEN_PVHVM
        def_bool y
index 7322755f337af760db6086450591c584c4dcda77..4b6e29ac0968c1a76451d3ff773652bc4afed138 100644 (file)
@@ -13,13 +13,13 @@ CFLAGS_mmu.o                        := $(nostackp)
 obj-y          := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        time.o xen-asm.o xen-asm_$(BITS).o \
                        grant-table.o suspend.o platform-pci-unplug.o \
-                       p2m.o
+                       p2m.o apic.o
 
 obj-$(CONFIG_EVENT_TRACING) += trace.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
 obj-$(CONFIG_XEN_DEBUG_FS)     += debugfs.o
-obj-$(CONFIG_XEN_DOM0)         += apic.o vga.o
+obj-$(CONFIG_XEN_DOM0)         += vga.o
 obj-$(CONFIG_SWIOTLB_XEN)      += pci-swiotlb-xen.o
 obj-$(CONFIG_XEN_EFI)          += efi.o
index 0b95c9b8283fe2afe885d9a8ae98393c14ecc498..11d6fb4e8483d529f833cbc1276ea4ffd3c68102 100644 (file)
@@ -483,6 +483,7 @@ static void set_aliased_prot(void *v, pgprot_t prot)
        pte_t pte;
        unsigned long pfn;
        struct page *page;
+       unsigned char dummy;
 
        ptep = lookup_address((unsigned long)v, &level);
        BUG_ON(ptep == NULL);
@@ -492,6 +493,32 @@ static void set_aliased_prot(void *v, pgprot_t prot)
 
        pte = pfn_pte(pfn, prot);
 
+       /*
+        * Careful: update_va_mapping() will fail if the virtual address
+        * we're poking isn't populated in the page tables.  We don't
+        * need to worry about the direct map (that's always in the page
+        * tables), but we need to be careful about vmap space.  In
+        * particular, the top level page table can lazily propagate
+        * entries between processes, so if we've switched mms since we
+        * vmapped the target in the first place, we might not have the
+        * top-level page table entry populated.
+        *
+        * We disable preemption because we want the same mm active when
+        * we probe the target and when we issue the hypercall.  We'll
+        * have the same nominal mm, but if we're a kernel thread, lazy
+        * mm dropping could change our pgd.
+        *
+        * Out of an abundance of caution, this uses __get_user() to fault
+        * in the target address just in case there's some obscure case
+        * in which the target address isn't readable.
+        */
+
+       preempt_disable();
+
+       pagefault_disable();    /* Avoid warnings due to being atomic. */
+       __get_user(dummy, (unsigned char __user __force *)v);
+       pagefault_enable();
+
        if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
                BUG();
 
@@ -503,6 +530,8 @@ static void set_aliased_prot(void *v, pgprot_t prot)
                                BUG();
        } else
                kmap_flush_unused();
+
+       preempt_enable();
 }
 
 static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
@@ -510,6 +539,17 @@ static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
        const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
        int i;
 
+       /*
+        * We need to mark the all aliases of the LDT pages RO.  We
+        * don't need to call vm_flush_aliases(), though, since that's
+        * only responsible for flushing aliases out the TLBs, not the
+        * page tables, and Xen will flush the TLB for us if needed.
+        *
+        * To avoid confusing future readers: none of this is necessary
+        * to load the LDT.  The hypervisor only checks this when the
+        * LDT is faulted in due to subsequent descriptor access.
+        */
+
        for(i = 0; i < entries; i += entries_per_page)
                set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
 }
index c20fe29e65f48b4706789e0ad59bb33b1a3acc18..2292721b1d103844ade9f8a7f436a649c811f77d 100644 (file)
@@ -101,17 +101,15 @@ struct dom0_vga_console_info;
 
 #ifdef CONFIG_XEN_DOM0
 void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
-void __init xen_init_apic(void);
 #else
 static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
                                       size_t size)
 {
 }
-static inline void __init xen_init_apic(void)
-{
-}
 #endif
 
+void __init xen_init_apic(void);
+
 #ifdef CONFIG_XEN_EFI
 extern void xen_efi_init(void);
 #else
index 14d15bf1a95bfb408bc6ac56f41ad51545228e6b..5b478accd5fcae8237ca010330a1c99d299fa6b4 100644 (file)
@@ -19,6 +19,7 @@ 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 += percpu.h
 generic-y += preempt.h
 generic-y += resource.h
diff --git a/arch/xtensa/include/asm/mm-arch-hooks.h b/arch/xtensa/include/asm/mm-arch-hooks.h
deleted file mode 100644 (file)
index d2e5cfd..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Architecture specific mm hooks
- *
- * Copyright (C) 2015, IBM Corporation
- * Author: Laurent Dufour <ldufour@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_XTENSA_MM_ARCH_HOOKS_H
-#define _ASM_XTENSA_MM_ARCH_HOOKS_H
-
-#endif /* _ASM_XTENSA_MM_ARCH_HOOKS_H */
index 0436c21db7f23b9c5fddf5fce48bc4b21541cd9f..719b7152aed14060cc957dd4acd349f6ab099d64 100644 (file)
@@ -51,7 +51,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
        unsigned long idx = BIO_POOL_NONE;
        unsigned inline_vecs;
 
-       if (!bs) {
+       if (!bs || !bs->bio_integrity_pool) {
                bip = kmalloc(sizeof(struct bio_integrity_payload) +
                              sizeof(struct bio_vec) * nr_vecs, gfp_mask);
                inline_vecs = nr_vecs;
@@ -104,7 +104,7 @@ void bio_integrity_free(struct bio *bio)
                kfree(page_address(bip->bip_vec->bv_page) +
                      bip->bip_vec->bv_offset);
 
-       if (bs) {
+       if (bs && bs->bio_integrity_pool) {
                if (bip->bip_slab != BIO_POOL_NONE)
                        bvec_free(bs->bvec_integrity_pool, bip->bip_vec,
                                  bip->bip_slab);
index 2a00d349cd6883cba32d9fd477251889a1c58081..d6e5ba3399f0ae151ea040e2ec1fd1df1c3dba6a 100644 (file)
@@ -1831,8 +1831,9 @@ EXPORT_SYMBOL(bio_endio);
  * Allocates and returns a new bio which represents @sectors from the start of
  * @bio, and updates @bio to represent the remaining sectors.
  *
- * The newly allocated bio will point to @bio's bi_io_vec; it is the caller's
- * responsibility to ensure that @bio is not freed before the split.
+ * Unless this is a discard request the newly allocated bio will point
+ * to @bio's bi_io_vec; it is the caller's responsibility to ensure that
+ * @bio is not freed before the split.
  */
 struct bio *bio_split(struct bio *bio, int sectors,
                      gfp_t gfp, struct bio_set *bs)
@@ -1842,7 +1843,15 @@ struct bio *bio_split(struct bio *bio, int sectors,
        BUG_ON(sectors <= 0);
        BUG_ON(sectors >= bio_sectors(bio));
 
-       split = bio_clone_fast(bio, gfp, bs);
+       /*
+        * Discards need a mutable bio_vec to accommodate the payload
+        * required by the DSM TRIM and UNMAP commands.
+        */
+       if (bio->bi_rw & REQ_DISCARD)
+               split = bio_clone_bioset(bio, gfp, bs);
+       else
+               split = bio_clone_fast(bio, gfp, bs);
+
        if (!split)
                return NULL;
 
@@ -2009,6 +2018,7 @@ int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css)
        bio->bi_css = blkcg_css;
        return 0;
 }
+EXPORT_SYMBOL_GPL(bio_associate_blkcg);
 
 /**
  * bio_associate_current - associate a bio with %current
@@ -2039,6 +2049,7 @@ int bio_associate_current(struct bio *bio)
        bio->bi_css = task_get_css(current, blkio_cgrp_id);
        return 0;
 }
+EXPORT_SYMBOL_GPL(bio_associate_current);
 
 /**
  * bio_disassociate_task - undo bio_associate_current()
index 9f97da52d006281b1ab3e2911d85934216e3931a..d6283b3f5db50674d18ae485970f1e24ed44569d 100644 (file)
 
 #define MAX_KEY_LEN 100
 
+/*
+ * blkcg_pol_mutex protects blkcg_policy[] and policy [de]activation.
+ * blkcg_pol_register_mutex nests outside of it and synchronizes entire
+ * policy [un]register operations including cgroup file additions /
+ * removals.  Putting cgroup file registration outside blkcg_pol_mutex
+ * allows grabbing it from cgroup callbacks.
+ */
+static DEFINE_MUTEX(blkcg_pol_register_mutex);
 static DEFINE_MUTEX(blkcg_pol_mutex);
 
 struct blkcg blkcg_root;
@@ -38,6 +46,8 @@ struct cgroup_subsys_state * const blkcg_root_css = &blkcg_root.css;
 
 static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
 
+static LIST_HEAD(all_blkcgs);          /* protected by blkcg_pol_mutex */
+
 static bool blkcg_policy_enabled(struct request_queue *q,
                                 const struct blkcg_policy *pol)
 {
@@ -453,20 +463,7 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css,
        struct blkcg_gq *blkg;
        int i;
 
-       /*
-        * XXX: We invoke cgroup_add/rm_cftypes() under blkcg_pol_mutex
-        * which ends up putting cgroup's internal cgroup_tree_mutex under
-        * it; however, cgroup_tree_mutex is nested above cgroup file
-        * active protection and grabbing blkcg_pol_mutex from a cgroup
-        * file operation creates a possible circular dependency.  cgroup
-        * internal locking is planned to go through further simplification
-        * and this issue should go away soon.  For now, let's trylock
-        * blkcg_pol_mutex and restart the write on failure.
-        *
-        * http://lkml.kernel.org/g/5363C04B.4010400@oracle.com
-        */
-       if (!mutex_trylock(&blkcg_pol_mutex))
-               return restart_syscall();
+       mutex_lock(&blkcg_pol_mutex);
        spin_lock_irq(&blkcg->lock);
 
        /*
@@ -721,8 +718,12 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
                return -EINVAL;
 
        disk = get_gendisk(MKDEV(major, minor), &part);
-       if (!disk || part)
+       if (!disk)
+               return -EINVAL;
+       if (part) {
+               put_disk(disk);
                return -EINVAL;
+       }
 
        rcu_read_lock();
        spin_lock_irq(disk->queue->queue_lock);
@@ -822,8 +823,17 @@ static void blkcg_css_free(struct cgroup_subsys_state *css)
 {
        struct blkcg *blkcg = css_to_blkcg(css);
 
-       if (blkcg != &blkcg_root)
+       mutex_lock(&blkcg_pol_mutex);
+       list_del(&blkcg->all_blkcgs_node);
+       mutex_unlock(&blkcg_pol_mutex);
+
+       if (blkcg != &blkcg_root) {
+               int i;
+
+               for (i = 0; i < BLKCG_MAX_POLS; i++)
+                       kfree(blkcg->pd[i]);
                kfree(blkcg);
+       }
 }
 
 static struct cgroup_subsys_state *
@@ -833,6 +843,8 @@ blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
        struct cgroup_subsys_state *ret;
        int i;
 
+       mutex_lock(&blkcg_pol_mutex);
+
        if (!parent_css) {
                blkcg = &blkcg_root;
                goto done;
@@ -875,14 +887,17 @@ done:
 #ifdef CONFIG_CGROUP_WRITEBACK
        INIT_LIST_HEAD(&blkcg->cgwb_list);
 #endif
+       list_add_tail(&blkcg->all_blkcgs_node, &all_blkcgs);
+
+       mutex_unlock(&blkcg_pol_mutex);
        return &blkcg->css;
 
 free_pd_blkcg:
        for (i--; i >= 0; i--)
                kfree(blkcg->pd[i]);
-
 free_blkcg:
        kfree(blkcg);
+       mutex_unlock(&blkcg_pol_mutex);
        return ret;
 }
 
@@ -1037,10 +1052,8 @@ int blkcg_activate_policy(struct request_queue *q,
                          const struct blkcg_policy *pol)
 {
        LIST_HEAD(pds);
-       LIST_HEAD(cpds);
        struct blkcg_gq *blkg;
        struct blkg_policy_data *pd, *nd;
-       struct blkcg_policy_data *cpd, *cnd;
        int cnt = 0, ret;
 
        if (blkcg_policy_enabled(q, pol))
@@ -1053,10 +1066,7 @@ int blkcg_activate_policy(struct request_queue *q,
                cnt++;
        spin_unlock_irq(q->queue_lock);
 
-       /*
-        * Allocate per-blkg and per-blkcg policy data
-        * for all existing blkgs.
-        */
+       /* allocate per-blkg policy data for all existing blkgs */
        while (cnt--) {
                pd = kzalloc_node(pol->pd_size, GFP_KERNEL, q->node);
                if (!pd) {
@@ -1064,15 +1074,6 @@ int blkcg_activate_policy(struct request_queue *q,
                        goto out_free;
                }
                list_add_tail(&pd->alloc_node, &pds);
-
-               if (!pol->cpd_size)
-                       continue;
-               cpd = kzalloc_node(pol->cpd_size, GFP_KERNEL, q->node);
-               if (!cpd) {
-                       ret = -ENOMEM;
-                       goto out_free;
-               }
-               list_add_tail(&cpd->alloc_node, &cpds);
        }
 
        /*
@@ -1082,32 +1083,17 @@ int blkcg_activate_policy(struct request_queue *q,
        spin_lock_irq(q->queue_lock);
 
        list_for_each_entry(blkg, &q->blkg_list, q_node) {
-               if (WARN_ON(list_empty(&pds)) ||
-                   WARN_ON(pol->cpd_size && list_empty(&cpds))) {
+               if (WARN_ON(list_empty(&pds))) {
                        /* umm... this shouldn't happen, just abort */
                        ret = -ENOMEM;
                        goto out_unlock;
                }
-               cpd = list_first_entry(&cpds, struct blkcg_policy_data,
-                                      alloc_node);
-               list_del_init(&cpd->alloc_node);
                pd = list_first_entry(&pds, struct blkg_policy_data, alloc_node);
                list_del_init(&pd->alloc_node);
 
                /* grab blkcg lock too while installing @pd on @blkg */
                spin_lock(&blkg->blkcg->lock);
 
-               if (!pol->cpd_size)
-                       goto no_cpd;
-               if (!blkg->blkcg->pd[pol->plid]) {
-                       /* Per-policy per-blkcg data */
-                       blkg->blkcg->pd[pol->plid] = cpd;
-                       cpd->plid = pol->plid;
-                       pol->cpd_init_fn(blkg->blkcg);
-               } else { /* must free it as it has already been extracted */
-                       kfree(cpd);
-               }
-no_cpd:
                blkg->pd[pol->plid] = pd;
                pd->blkg = blkg;
                pd->plid = pol->plid;
@@ -1124,8 +1110,6 @@ out_free:
        blk_queue_bypass_end(q);
        list_for_each_entry_safe(pd, nd, &pds, alloc_node)
                kfree(pd);
-       list_for_each_entry_safe(cpd, cnd, &cpds, alloc_node)
-               kfree(cpd);
        return ret;
 }
 EXPORT_SYMBOL_GPL(blkcg_activate_policy);
@@ -1162,8 +1146,6 @@ void blkcg_deactivate_policy(struct request_queue *q,
 
                kfree(blkg->pd[pol->plid]);
                blkg->pd[pol->plid] = NULL;
-               kfree(blkg->blkcg->pd[pol->plid]);
-               blkg->blkcg->pd[pol->plid] = NULL;
 
                spin_unlock(&blkg->blkcg->lock);
        }
@@ -1182,11 +1164,13 @@ EXPORT_SYMBOL_GPL(blkcg_deactivate_policy);
  */
 int blkcg_policy_register(struct blkcg_policy *pol)
 {
+       struct blkcg *blkcg;
        int i, ret;
 
        if (WARN_ON(pol->pd_size < sizeof(struct blkg_policy_data)))
                return -EINVAL;
 
+       mutex_lock(&blkcg_pol_register_mutex);
        mutex_lock(&blkcg_pol_mutex);
 
        /* find an empty slot */
@@ -1195,19 +1179,49 @@ int blkcg_policy_register(struct blkcg_policy *pol)
                if (!blkcg_policy[i])
                        break;
        if (i >= BLKCG_MAX_POLS)
-               goto out_unlock;
+               goto err_unlock;
 
-       /* register and update blkgs */
+       /* register @pol */
        pol->plid = i;
-       blkcg_policy[i] = pol;
+       blkcg_policy[pol->plid] = pol;
+
+       /* allocate and install cpd's */
+       if (pol->cpd_size) {
+               list_for_each_entry(blkcg, &all_blkcgs, all_blkcgs_node) {
+                       struct blkcg_policy_data *cpd;
+
+                       cpd = kzalloc(pol->cpd_size, GFP_KERNEL);
+                       if (!cpd) {
+                               mutex_unlock(&blkcg_pol_mutex);
+                               goto err_free_cpds;
+                       }
+
+                       blkcg->pd[pol->plid] = cpd;
+                       cpd->plid = pol->plid;
+                       pol->cpd_init_fn(blkcg);
+               }
+       }
+
+       mutex_unlock(&blkcg_pol_mutex);
 
        /* everything is in place, add intf files for the new policy */
        if (pol->cftypes)
                WARN_ON(cgroup_add_legacy_cftypes(&blkio_cgrp_subsys,
                                                  pol->cftypes));
-       ret = 0;
-out_unlock:
+       mutex_unlock(&blkcg_pol_register_mutex);
+       return 0;
+
+err_free_cpds:
+       if (pol->cpd_size) {
+               list_for_each_entry(blkcg, &all_blkcgs, all_blkcgs_node) {
+                       kfree(blkcg->pd[pol->plid]);
+                       blkcg->pd[pol->plid] = NULL;
+               }
+       }
+       blkcg_policy[pol->plid] = NULL;
+err_unlock:
        mutex_unlock(&blkcg_pol_mutex);
+       mutex_unlock(&blkcg_pol_register_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(blkcg_policy_register);
@@ -1220,7 +1234,9 @@ EXPORT_SYMBOL_GPL(blkcg_policy_register);
  */
 void blkcg_policy_unregister(struct blkcg_policy *pol)
 {
-       mutex_lock(&blkcg_pol_mutex);
+       struct blkcg *blkcg;
+
+       mutex_lock(&blkcg_pol_register_mutex);
 
        if (WARN_ON(blkcg_policy[pol->plid] != pol))
                goto out_unlock;
@@ -1229,9 +1245,19 @@ void blkcg_policy_unregister(struct blkcg_policy *pol)
        if (pol->cftypes)
                cgroup_rm_cftypes(pol->cftypes);
 
-       /* unregister and update blkgs */
+       /* remove cpds and unregister */
+       mutex_lock(&blkcg_pol_mutex);
+
+       if (pol->cpd_size) {
+               list_for_each_entry(blkcg, &all_blkcgs, all_blkcgs_node) {
+                       kfree(blkcg->pd[pol->plid]);
+                       blkcg->pd[pol->plid] = NULL;
+               }
+       }
        blkcg_policy[pol->plid] = NULL;
-out_unlock:
+
        mutex_unlock(&blkcg_pol_mutex);
+out_unlock:
+       mutex_unlock(&blkcg_pol_register_mutex);
 }
 EXPORT_SYMBOL_GPL(blkcg_policy_unregister);
index 82819e68f58b10c59edaa32c65b5a783306c99ae..627ed0c593fb4c05dd46e1da9eb75ddf2e6c1269 100644 (file)
@@ -3370,7 +3370,7 @@ EXPORT_SYMBOL(blk_post_runtime_resume);
 int __init blk_dev_init(void)
 {
        BUILD_BUG_ON(__REQ_NR_BITS > 8 *
-                       sizeof(((struct request *)0)->cmd_flags));
+                       FIELD_SIZEOF(struct request, cmd_flags));
 
        /* used for unplugging and affects IO latency/throughput - HIGHPRI */
        kblockd_workqueue = alloc_workqueue("kblockd",
index f53779692c772a1cc06ec341f9fab307b2ceef91..7d842db59699692dd0ebce5daf6a71443f0e4314 100644 (file)
@@ -1998,7 +1998,7 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
                goto err_hctxs;
 
        setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q);
-       blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30000);
+       blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ);
 
        q->nr_queues = nr_cpu_ids;
        q->nr_hw_queues = set->nr_hw_queues;
index 12600bfffca93f4547e2325eeda9669ff443a7a7..e0057d035200c4dd5e42d191f0395a7769489905 100644 (file)
@@ -241,8 +241,8 @@ EXPORT_SYMBOL(blk_queue_bounce_limit);
  * Description:
  *    Enables a low level driver to set a hard upper limit,
  *    max_hw_sectors, on the size of requests.  max_hw_sectors is set by
- *    the device driver based upon the combined capabilities of I/O
- *    controller and storage device.
+ *    the device driver based upon the capabilities of the I/O
+ *    controller.
  *
  *    max_sectors is a soft limit imposed by the block layer for
  *    filesystem type requests.  This value can be overridden on a
index a3da6770bc9ed2bf66d59e8e74461829eeb4fe4e..b8efe36ce1142d0c6b0b8e45ec23965ec7135c40 100644 (file)
@@ -393,8 +393,6 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv,
        struct scatterlist *cipher = areq_ctx->cipher;
        struct scatterlist *hsg = areq_ctx->hsg;
        struct scatterlist *tsg = areq_ctx->tsg;
-       struct scatterlist *assoc1;
-       struct scatterlist *assoc2;
        unsigned int ivsize = crypto_aead_ivsize(authenc_esn);
        unsigned int cryptlen = req->cryptlen;
        struct page *dstp;
@@ -412,27 +410,19 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv,
                cryptlen += ivsize;
        }
 
-       if (sg_is_last(assoc))
-               return -EINVAL;
-
-       assoc1 = assoc + 1;
-       if (sg_is_last(assoc1))
-               return -EINVAL;
-
-       assoc2 = assoc + 2;
-       if (!sg_is_last(assoc2))
+       if (assoc->length < 12)
                return -EINVAL;
 
        sg_init_table(hsg, 2);
-       sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset);
-       sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset);
+       sg_set_page(hsg, sg_page(assoc), 4, assoc->offset);
+       sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8);
 
        sg_init_table(tsg, 1);
-       sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset);
+       sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4);
 
        areq_ctx->cryptlen = cryptlen;
-       areq_ctx->headlen = assoc->length + assoc2->length;
-       areq_ctx->trailen = assoc1->length;
+       areq_ctx->headlen = 8;
+       areq_ctx->trailen = 4;
        areq_ctx->sg = dst;
 
        areq_ctx->complete = authenc_esn_geniv_ahash_done;
@@ -563,8 +553,6 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
        struct scatterlist *cipher = areq_ctx->cipher;
        struct scatterlist *hsg = areq_ctx->hsg;
        struct scatterlist *tsg = areq_ctx->tsg;
-       struct scatterlist *assoc1;
-       struct scatterlist *assoc2;
        unsigned int ivsize = crypto_aead_ivsize(authenc_esn);
        struct page *srcp;
        u8 *vsrc;
@@ -580,27 +568,19 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
                cryptlen += ivsize;
        }
 
-       if (sg_is_last(assoc))
-               return -EINVAL;
-
-       assoc1 = assoc + 1;
-       if (sg_is_last(assoc1))
-               return -EINVAL;
-
-       assoc2 = assoc + 2;
-       if (!sg_is_last(assoc2))
+       if (assoc->length < 12)
                return -EINVAL;
 
        sg_init_table(hsg, 2);
-       sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset);
-       sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset);
+       sg_set_page(hsg, sg_page(assoc), 4, assoc->offset);
+       sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8);
 
        sg_init_table(tsg, 1);
-       sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset);
+       sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4);
 
        areq_ctx->cryptlen = cryptlen;
-       areq_ctx->headlen = assoc->length + assoc2->length;
-       areq_ctx->trailen = assoc1->length;
+       areq_ctx->headlen = 8;
+       areq_ctx->trailen = 4;
        areq_ctx->sg = src;
 
        areq_ctx->complete = authenc_esn_verify_ahash_done;
index 569ee090343fee43c318f7a1bafee0eadb65e1f6..46b58abb08c5e05efb9111f76e788a3601f6046c 100644 (file)
@@ -352,13 +352,16 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
                                pdata->mmio_size = resource_size(rentry->res);
                        pdata->mmio_base = ioremap(rentry->res->start,
                                                   pdata->mmio_size);
-                       if (!pdata->mmio_base)
-                               goto err_out;
                        break;
                }
 
        acpi_dev_free_resource_list(&resource_list);
 
+       if (!pdata->mmio_base) {
+               ret = -ENOMEM;
+               goto err_out;
+       }
+
        pdata->dev_desc = dev_desc;
 
        if (dev_desc->setup)
index 717afcdb5f4a9657a9ca6f6af9825e109eba9688..88dbbb115285a3ce54ae5c35260692163bae16ca 100644 (file)
@@ -231,7 +231,7 @@ int acpi_device_set_power(struct acpi_device *device, int state)
                dev_warn(&device->dev, "Failed to change power state to %s\n",
                         acpi_power_state_string(state));
        } else {
-               device->power.state = state;
+               device->power.state = target_state;
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Device [%s] transitioned to %s\n",
                                  device->pnp.bus_id,
index 2161fa178c8d07a5a66d605ca8dbb6a42beea4db..628a42c41ab126d12997ab02fd805df6af698c98 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/acpi.h>
 #include <linux/sort.h>
+#include <linux/pmem.h>
 #include <linux/io.h>
 #include "nfit.h"
 
@@ -305,6 +306,23 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
        return true;
 }
 
+static bool add_flush(struct acpi_nfit_desc *acpi_desc,
+               struct acpi_nfit_flush_address *flush)
+{
+       struct device *dev = acpi_desc->dev;
+       struct nfit_flush *nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush),
+                       GFP_KERNEL);
+
+       if (!nfit_flush)
+               return false;
+       INIT_LIST_HEAD(&nfit_flush->list);
+       nfit_flush->flush = flush;
+       list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
+       dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__,
+                       flush->device_handle, flush->hint_count);
+       return true;
+}
+
 static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
                const void *end)
 {
@@ -338,7 +356,8 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
                        return err;
                break;
        case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
-               dev_dbg(dev, "%s: flush\n", __func__);
+               if (!add_flush(acpi_desc, table))
+                       return err;
                break;
        case ACPI_NFIT_TYPE_SMBIOS:
                dev_dbg(dev, "%s: smbios\n", __func__);
@@ -389,6 +408,7 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
 {
        u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
        struct nfit_memdev *nfit_memdev;
+       struct nfit_flush *nfit_flush;
        struct nfit_dcr *nfit_dcr;
        struct nfit_bdw *nfit_bdw;
        struct nfit_idt *nfit_idt;
@@ -442,6 +462,14 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
                        nfit_mem->idt_bdw = nfit_idt->idt;
                        break;
                }
+
+               list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
+                       if (nfit_flush->flush->device_handle !=
+                                       nfit_memdev->memdev->device_handle)
+                               continue;
+                       nfit_mem->nfit_flush = nfit_flush;
+                       break;
+               }
                break;
        }
 
@@ -978,6 +1006,24 @@ static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio)
        return mmio->base_offset + line_offset + table_offset + sub_line_offset;
 }
 
+static void wmb_blk(struct nfit_blk *nfit_blk)
+{
+
+       if (nfit_blk->nvdimm_flush) {
+               /*
+                * The first wmb() is needed to 'sfence' all previous writes
+                * such that they are architecturally visible for the platform
+                * buffer flush.  Note that we've already arranged for pmem
+                * writes to avoid the cache via arch_memcpy_to_pmem().  The
+                * final wmb() ensures ordering for the NVDIMM flush write.
+                */
+               wmb();
+               writeq(1, nfit_blk->nvdimm_flush);
+               wmb();
+       } else
+               wmb_pmem();
+}
+
 static u64 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
 {
        struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
@@ -1012,7 +1058,10 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
                offset = to_interleave_offset(offset, mmio);
 
        writeq(cmd, mmio->base + offset);
-       /* FIXME: conditionally perform read-back if mandated by firmware */
+       wmb_blk(nfit_blk);
+
+       if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH)
+               readq(mmio->base + offset);
 }
 
 static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
@@ -1026,7 +1075,6 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
 
        base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES
                + lane * mmio->size;
-       /* TODO: non-temporal access, flush hints, cache management etc... */
        write_blk_ctl(nfit_blk, lane, dpa, len, rw);
        while (len) {
                unsigned int c;
@@ -1045,13 +1093,19 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
                }
 
                if (rw)
-                       memcpy(mmio->aperture + offset, iobuf + copied, c);
+                       memcpy_to_pmem(mmio->aperture + offset,
+                                       iobuf + copied, c);
                else
-                       memcpy(iobuf + copied, mmio->aperture + offset, c);
+                       memcpy_from_pmem(iobuf + copied,
+                                       mmio->aperture + offset, c);
 
                copied += c;
                len -= c;
        }
+
+       if (rw)
+               wmb_blk(nfit_blk);
+
        rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
        return rc;
 }
@@ -1124,7 +1178,7 @@ static void nfit_spa_unmap(struct acpi_nfit_desc *acpi_desc,
 }
 
 static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
+               struct acpi_nfit_system_address *spa, enum spa_map_type type)
 {
        resource_size_t start = spa->address;
        resource_size_t n = spa->length;
@@ -1152,8 +1206,15 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
        if (!res)
                goto err_mem;
 
-       /* TODO: cacheability based on the spa type */
-       spa_map->iomem = ioremap_nocache(start, n);
+       if (type == SPA_MAP_APERTURE) {
+               /*
+                * TODO: memremap_pmem() support, but that requires cache
+                * flushing when the aperture is moved.
+                */
+               spa_map->iomem = ioremap_wc(start, n);
+       } else
+               spa_map->iomem = ioremap_nocache(start, n);
+
        if (!spa_map->iomem)
                goto err_map;
 
@@ -1171,6 +1232,7 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
  * nfit_spa_map - interleave-aware managed-mappings of acpi_nfit_system_address ranges
  * @nvdimm_bus: NFIT-bus that provided the spa table entry
  * @nfit_spa: spa table to map
+ * @type: aperture or control region
  *
  * In the case where block-data-window apertures and
  * dimm-control-regions are interleaved they will end up sharing a
@@ -1180,12 +1242,12 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
  * unbound.
  */
 static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
-               struct acpi_nfit_system_address *spa)
+               struct acpi_nfit_system_address *spa, enum spa_map_type type)
 {
        void __iomem *iomem;
 
        mutex_lock(&acpi_desc->spa_map_mutex);
-       iomem = __nfit_spa_map(acpi_desc, spa);
+       iomem = __nfit_spa_map(acpi_desc, spa, type);
        mutex_unlock(&acpi_desc->spa_map_mutex);
 
        return iomem;
@@ -1206,12 +1268,35 @@ static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio,
        return 0;
 }
 
+static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
+               struct nvdimm *nvdimm, struct nfit_blk *nfit_blk)
+{
+       struct nd_cmd_dimm_flags flags;
+       int rc;
+
+       memset(&flags, 0, sizeof(flags));
+       rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
+                       sizeof(flags));
+
+       if (rc >= 0 && flags.status == 0)
+               nfit_blk->dimm_flags = flags.flags;
+       else if (rc == -ENOTTY) {
+               /* fall back to a conservative default */
+               nfit_blk->dimm_flags = ND_BLK_DCR_LATCH;
+               rc = 0;
+       } else
+               rc = -ENXIO;
+
+       return rc;
+}
+
 static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
                struct device *dev)
 {
        struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
        struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
        struct nd_blk_region *ndbr = to_nd_blk_region(dev);
+       struct nfit_flush *nfit_flush;
        struct nfit_blk_mmio *mmio;
        struct nfit_blk *nfit_blk;
        struct nfit_mem *nfit_mem;
@@ -1223,8 +1308,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
        if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) {
                dev_dbg(dev, "%s: missing%s%s%s\n", __func__,
                                nfit_mem ? "" : " nfit_mem",
-                               nfit_mem->dcr ? "" : " dcr",
-                               nfit_mem->bdw ? "" : " bdw");
+                               (nfit_mem && nfit_mem->dcr) ? "" : " dcr",
+                               (nfit_mem && nfit_mem->bdw) ? "" : " bdw");
                return -ENXIO;
        }
 
@@ -1237,7 +1322,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
        /* map block aperture memory */
        nfit_blk->bdw_offset = nfit_mem->bdw->offset;
        mmio = &nfit_blk->mmio[BDW];
-       mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw);
+       mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw,
+                       SPA_MAP_APERTURE);
        if (!mmio->base) {
                dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
                                nvdimm_name(nvdimm));
@@ -1259,7 +1345,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
        nfit_blk->cmd_offset = nfit_mem->dcr->command_offset;
        nfit_blk->stat_offset = nfit_mem->dcr->status_offset;
        mmio = &nfit_blk->mmio[DCR];
-       mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr);
+       mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr,
+                       SPA_MAP_CONTROL);
        if (!mmio->base) {
                dev_dbg(dev, "%s: %s failed to map dcr\n", __func__,
                                nvdimm_name(nvdimm));
@@ -1277,6 +1364,24 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
                return rc;
        }
 
+       rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk);
+       if (rc < 0) {
+               dev_dbg(dev, "%s: %s failed get DIMM flags\n",
+                               __func__, nvdimm_name(nvdimm));
+               return rc;
+       }
+
+       nfit_flush = nfit_mem->nfit_flush;
+       if (nfit_flush && nfit_flush->flush->hint_count != 0) {
+               nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev,
+                               nfit_flush->flush->hint_address[0], 8);
+               if (!nfit_blk->nvdimm_flush)
+                       return -ENOMEM;
+       }
+
+       if (!arch_has_pmem_api() && !nfit_blk->nvdimm_flush)
+               dev_warn(dev, "unable to guarantee persistence of writes\n");
+
        if (mmio->line_size == 0)
                return 0;
 
@@ -1459,6 +1564,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
        INIT_LIST_HEAD(&acpi_desc->dcrs);
        INIT_LIST_HEAD(&acpi_desc->bdws);
        INIT_LIST_HEAD(&acpi_desc->idts);
+       INIT_LIST_HEAD(&acpi_desc->flushes);
        INIT_LIST_HEAD(&acpi_desc->memdevs);
        INIT_LIST_HEAD(&acpi_desc->dimms);
        mutex_init(&acpi_desc->spa_map_mutex);
index 81f2e8c5a79c724b7c66970698e6ca8a3f69520f..79b6d83875c1de1aed4bc67e091a4d2e3aa88204 100644 (file)
@@ -40,6 +40,10 @@ enum nfit_uuids {
        NFIT_UUID_MAX,
 };
 
+enum {
+       ND_BLK_DCR_LATCH = 2,
+};
+
 struct nfit_spa {
        struct acpi_nfit_system_address *spa;
        struct list_head list;
@@ -60,6 +64,11 @@ struct nfit_idt {
        struct list_head list;
 };
 
+struct nfit_flush {
+       struct acpi_nfit_flush_address *flush;
+       struct list_head list;
+};
+
 struct nfit_memdev {
        struct acpi_nfit_memory_map *memdev;
        struct list_head list;
@@ -77,6 +86,7 @@ struct nfit_mem {
        struct acpi_nfit_system_address *spa_bdw;
        struct acpi_nfit_interleave *idt_dcr;
        struct acpi_nfit_interleave *idt_bdw;
+       struct nfit_flush *nfit_flush;
        struct list_head list;
        struct acpi_device *adev;
        unsigned long dsm_mask;
@@ -88,6 +98,7 @@ struct acpi_nfit_desc {
        struct mutex spa_map_mutex;
        struct list_head spa_maps;
        struct list_head memdevs;
+       struct list_head flushes;
        struct list_head dimms;
        struct list_head spas;
        struct list_head dcrs;
@@ -109,7 +120,7 @@ struct nfit_blk {
        struct nfit_blk_mmio {
                union {
                        void __iomem *base;
-                       void *aperture;
+                       void __pmem  *aperture;
                };
                u64 size;
                u64 base_offset;
@@ -123,6 +134,13 @@ struct nfit_blk {
        u64 bdw_offset; /* post interleave offset */
        u64 stat_offset;
        u64 cmd_offset;
+       void __iomem *nvdimm_flush;
+       u32 dimm_flags;
+};
+
+enum spa_map_type {
+       SPA_MAP_CONTROL,
+       SPA_MAP_APERTURE,
 };
 
 struct nfit_spa_mapping {
index c262e4acd68d827cba1273d79e28515c6ebe95fa..3b8963f21b36702c2ed84970908672a4ab21c9f9 100644 (file)
@@ -175,10 +175,14 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
        if (!addr || !length)
                return;
 
-       acpi_reserve_region(addr, length, gas->space_id, 0, desc);
+       /* Resources are never freed */
+       if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+               request_region(addr, length, desc);
+       else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               request_mem_region(addr, length, desc);
 }
 
-static void __init acpi_reserve_resources(void)
+static int __init acpi_reserve_resources(void)
 {
        acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
                "ACPI PM1a_EVT_BLK");
@@ -207,7 +211,10 @@ static void __init acpi_reserve_resources(void)
        if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
                acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
                               acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
+
+       return 0;
 }
+fs_initcall_sync(acpi_reserve_resources);
 
 void acpi_os_printf(const char *fmt, ...)
 {
@@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(void)
 
 acpi_status __init acpi_os_initialize1(void)
 {
-       acpi_reserve_resources();
        kacpid_wq = alloc_workqueue("kacpid", 0, 1);
        kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
        kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
index 10561ce16ed135165cdbc8e558cb2aaea263d13b..f1c966e05078426455227d8f582a7ddd0f211cb2 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/device.h>
 #include <linux/export.h>
 #include <linux/ioport.h>
-#include <linux/list.h>
 #include <linux/slab.h>
 
 #ifdef CONFIG_X86
@@ -194,6 +193,7 @@ static bool acpi_decode_space(struct resource_win *win,
        u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16;
        bool wp = addr->info.mem.write_protect;
        u64 len = attr->address_length;
+       u64 start, end, offset = 0;
        struct resource *res = &win->res;
 
        /*
@@ -205,9 +205,6 @@ static bool acpi_decode_space(struct resource_win *win,
                pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n",
                         addr->min_address_fixed, addr->max_address_fixed, len);
 
-       res->start = attr->minimum;
-       res->end = attr->maximum;
-
        /*
         * For bridges that translate addresses across the bridge,
         * translation_offset is the offset that must be added to the
@@ -215,12 +212,22 @@ static bool acpi_decode_space(struct resource_win *win,
         * primary side. Non-bridge devices must list 0 for all Address
         * Translation offset bits.
         */
-       if (addr->producer_consumer == ACPI_PRODUCER) {
-               res->start += attr->translation_offset;
-               res->end += attr->translation_offset;
-       } else if (attr->translation_offset) {
+       if (addr->producer_consumer == ACPI_PRODUCER)
+               offset = attr->translation_offset;
+       else if (attr->translation_offset)
                pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n",
                         attr->translation_offset);
+       start = attr->minimum + offset;
+       end = attr->maximum + offset;
+
+       win->offset = offset;
+       res->start = start;
+       res->end = end;
+       if (sizeof(resource_size_t) < sizeof(u64) &&
+           (offset != win->offset || start != res->start || end != res->end)) {
+               pr_warn("acpi resource window ([%#llx-%#llx] ignored, not CPU addressable)\n",
+                       attr->minimum, attr->maximum);
+               return false;
        }
 
        switch (addr->resource_type) {
@@ -237,8 +244,6 @@ static bool acpi_decode_space(struct resource_win *win,
                return false;
        }
 
-       win->offset = attr->translation_offset;
-
        if (addr->producer_consumer == ACPI_PRODUCER)
                res->flags |= IORESOURCE_WINDOW;
 
@@ -622,164 +627,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
        return (type & types) ? 0 : 1;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
-
-struct reserved_region {
-       struct list_head node;
-       u64 start;
-       u64 end;
-};
-
-static LIST_HEAD(reserved_io_regions);
-static LIST_HEAD(reserved_mem_regions);
-
-static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
-                        char *desc)
-{
-       unsigned int length = end - start + 1;
-       struct resource *res;
-
-       res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
-               request_region(start, length, desc) :
-               request_mem_region(start, length, desc);
-       if (!res)
-               return -EIO;
-
-       res->flags &= ~flags;
-       return 0;
-}
-
-static int add_region_before(u64 start, u64 end, u8 space_id,
-                            unsigned long flags, char *desc,
-                            struct list_head *head)
-{
-       struct reserved_region *reg;
-       int error;
-
-       reg = kmalloc(sizeof(*reg), GFP_KERNEL);
-       if (!reg)
-               return -ENOMEM;
-
-       error = request_range(start, end, space_id, flags, desc);
-       if (error) {
-               kfree(reg);
-               return error;
-       }
-
-       reg->start = start;
-       reg->end = end;
-       list_add_tail(&reg->node, head);
-       return 0;
-}
-
-/**
- * acpi_reserve_region - Reserve an I/O or memory region as a system resource.
- * @start: Starting address of the region.
- * @length: Length of the region.
- * @space_id: Identifier of address space to reserve the region from.
- * @flags: Resource flags to clear for the region after requesting it.
- * @desc: Region description (for messages).
- *
- * Reserve an I/O or memory region as a system resource to prevent others from
- * using it.  If the new region overlaps with one of the regions (in the given
- * address space) already reserved by this routine, only the non-overlapping
- * parts of it will be reserved.
- *
- * Returned is either 0 (success) or a negative error code indicating a resource
- * reservation problem.  It is the code of the first encountered error, but the
- * routine doesn't abort until it has attempted to request all of the parts of
- * the new region that don't overlap with other regions reserved previously.
- *
- * The resources requested by this routine are never released.
- */
-int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
-                       unsigned long flags, char *desc)
-{
-       struct list_head *regions;
-       struct reserved_region *reg;
-       u64 end = start + length - 1;
-       int ret = 0, error = 0;
-
-       if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
-               regions = &reserved_io_regions;
-       else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
-               regions = &reserved_mem_regions;
-       else
-               return -EINVAL;
-
-       if (list_empty(regions))
-               return add_region_before(start, end, space_id, flags, desc, regions);
-
-       list_for_each_entry(reg, regions, node)
-               if (reg->start == end + 1) {
-                       /* The new region can be prepended to this one. */
-                       ret = request_range(start, end, space_id, flags, desc);
-                       if (!ret)
-                               reg->start = start;
-
-                       return ret;
-               } else if (reg->start > end) {
-                       /* No overlap.  Add the new region here and get out. */
-                       return add_region_before(start, end, space_id, flags,
-                                                desc, &reg->node);
-               } else if (reg->end == start - 1) {
-                       goto combine;
-               } else if (reg->end >= start) {
-                       goto overlap;
-               }
-
-       /* The new region goes after the last existing one. */
-       return add_region_before(start, end, space_id, flags, desc, regions);
-
- overlap:
-       /*
-        * The new region overlaps an existing one.
-        *
-        * The head part of the new region immediately preceding the existing
-        * overlapping one can be combined with it right away.
-        */
-       if (reg->start > start) {
-               error = request_range(start, reg->start - 1, space_id, flags, desc);
-               if (error)
-                       ret = error;
-               else
-                       reg->start = start;
-       }
-
- combine:
-       /*
-        * The new region is adjacent to an existing one.  If it extends beyond
-        * that region all the way to the next one, it is possible to combine
-        * all three of them.
-        */
-       while (reg->end < end) {
-               struct reserved_region *next = NULL;
-               u64 a = reg->end + 1, b = end;
-
-               if (!list_is_last(&reg->node, regions)) {
-                       next = list_next_entry(reg, node);
-                       if (next->start <= end)
-                               b = next->start - 1;
-               }
-               error = request_range(a, b, space_id, flags, desc);
-               if (!error) {
-                       if (next && next->start == b + 1) {
-                               reg->end = next->end;
-                               list_del(&next->node);
-                               kfree(next);
-                       } else {
-                               reg->end = end;
-                               break;
-                       }
-               } else if (next) {
-                       if (!ret)
-                               ret = error;
-
-                       reg = next;
-               } else {
-                       break;
-               }
-       }
-
-       return ret ? ret : error;
-}
-EXPORT_SYMBOL_GPL(acpi_reserve_region);
index 2649a068671d3914d5f1eae97e4d91b1c2c56ed1..ec256352f42367375bd3375ca7cad62cbd50bab7 100644 (file)
@@ -1019,6 +1019,29 @@ static bool acpi_of_match_device(struct acpi_device *adev,
        return false;
 }
 
+static bool __acpi_match_device_cls(const struct acpi_device_id *id,
+                                   struct acpi_hardware_id *hwid)
+{
+       int i, msk, byte_shift;
+       char buf[3];
+
+       if (!id->cls)
+               return false;
+
+       /* Apply class-code bitmask, before checking each class-code byte */
+       for (i = 1; i <= 3; i++) {
+               byte_shift = 8 * (3 - i);
+               msk = (id->cls_msk >> byte_shift) & 0xFF;
+               if (!msk)
+                       continue;
+
+               sprintf(buf, "%02x", (id->cls >> byte_shift) & msk);
+               if (strncmp(buf, &hwid->id[(i - 1) * 2], 2))
+                       return false;
+       }
+       return true;
+}
+
 static const struct acpi_device_id *__acpi_match_device(
        struct acpi_device *device,
        const struct acpi_device_id *ids,
@@ -1036,9 +1059,12 @@ static const struct acpi_device_id *__acpi_match_device(
 
        list_for_each_entry(hwid, &device->pnp.ids, list) {
                /* First, check the ACPI/PNP IDs provided by the caller. */
-               for (id = ids; id->id[0]; id++)
-                       if (!strcmp((char *) id->id, hwid->id))
+               for (id = ids; id->id[0] || id->cls; id++) {
+                       if (id->id[0] && !strcmp((char *) id->id, hwid->id))
                                return id;
+                       else if (id->cls && __acpi_match_device_cls(id, hwid))
+                               return id;
+               }
 
                /*
                 * Next, check ACPI_DT_NAMESPACE_HID and try to match the
@@ -2101,6 +2127,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                if (info->valid & ACPI_VALID_UID)
                        pnp->unique_id = kstrdup(info->unique_id.string,
                                                        GFP_KERNEL);
+               if (info->valid & ACPI_VALID_CLS)
+                       acpi_add_id(pnp, info->class_code.string);
 
                kfree(info);
 
index 815f75ef24119eab28ce3c0c2047295c6e464c58..2922f1f252d58aafd2d6c233404ae7ca21abb524 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 #include <acpi/video.h>
 
 ACPI_MODULE_NAME("video");
@@ -41,6 +42,7 @@ void acpi_video_unregister_backlight(void);
 
 static bool backlight_notifier_registered;
 static struct notifier_block backlight_nb;
+static struct work_struct backlight_notify_work;
 
 static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
 static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
@@ -262,6 +264,13 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        { },
 };
 
+/* This uses a workqueue to avoid various locking ordering issues */
+static void acpi_video_backlight_notify_work(struct work_struct *work)
+{
+       if (acpi_video_get_backlight_type() != acpi_backlight_video)
+               acpi_video_unregister_backlight();
+}
+
 static int acpi_video_backlight_notify(struct notifier_block *nb,
                                       unsigned long val, void *bd)
 {
@@ -269,9 +278,8 @@ static int acpi_video_backlight_notify(struct notifier_block *nb,
 
        /* A raw bl registering may change video -> native */
        if (backlight->props.type == BACKLIGHT_RAW &&
-           val == BACKLIGHT_REGISTERED &&
-           acpi_video_get_backlight_type() != acpi_backlight_video)
-               acpi_video_unregister_backlight();
+           val == BACKLIGHT_REGISTERED)
+               schedule_work(&backlight_notify_work);
 
        return NOTIFY_OK;
 }
@@ -304,6 +312,8 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void)
                acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
                                    ACPI_UINT32_MAX, find_video, NULL,
                                    &video_caps, NULL);
+               INIT_WORK(&backlight_notify_work,
+                         acpi_video_backlight_notify_work);
                backlight_nb.notifier_call = acpi_video_backlight_notify;
                backlight_nb.priority = 0;
                if (backlight_register_notifier(&backlight_nb) == 0)
index 6d17a3b65ef78c320200acc04ec404b739637442..15e40ee62a94e0c0ce20b07c7d4ff1ce03f78f6b 100644 (file)
@@ -48,7 +48,7 @@ config ATA_VERBOSE_ERROR
 
 config ATA_ACPI
        bool "ATA ACPI Support"
-       depends on ACPI && PCI
+       depends on ACPI
        default y
        help
          This option adds support for ATA-related ACPI objects.
index ce1e3a8859815ca5724e376de6d6ab0d549c9831..14b7305d2ba0b3cc24aa101e76c87e242f01f537 100644 (file)
@@ -92,7 +92,7 @@ static inline u32 brcm_sata_readreg(void __iomem *addr)
         * Other architectures (e.g., ARM) either do not support big endian, or
         * else leave I/O in little endian mode.
         */
-       if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
+       if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
                return __raw_readl(addr);
        else
                return readl_relaxed(addr);
@@ -101,7 +101,7 @@ static inline u32 brcm_sata_readreg(void __iomem *addr)
 static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
 {
        /* See brcm_sata_readreg() comments */
-       if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
+       if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
                __raw_writel(val, addr);
        else
                writel_relaxed(val, addr);
@@ -209,6 +209,7 @@ static void brcm_sata_init(struct brcm_ahci_priv *priv)
                           priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int brcm_ahci_suspend(struct device *dev)
 {
        struct ata_host *host = dev_get_drvdata(dev);
@@ -231,6 +232,7 @@ static int brcm_ahci_resume(struct device *dev)
        brcm_sata_phys_enable(priv);
        return ahci_platform_resume(dev);
 }
+#endif
 
 static struct scsi_host_template ahci_platform_sht = {
        AHCI_SHT(DRV_NAME),
index 614c78f510f049286f491d78ec9f3d395300a6f2..1befb114c3844c507939fe82924d60340edce15b 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/platform_device.h>
 #include <linux/libata.h>
 #include <linux/ahci_platform.h>
+#include <linux/acpi.h>
+#include <linux/pci_ids.h>
 #include "ahci.h"
 
 #define DRV_NAME "ahci"
@@ -79,12 +81,19 @@ static const struct of_device_id ahci_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
 
+static const struct acpi_device_id ahci_acpi_match[] = {
+       { ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, ahci_acpi_match);
+
 static struct platform_driver ahci_driver = {
        .probe = ahci_probe,
        .remove = ata_platform_remove_one,
        .driver = {
                .name = DRV_NAME,
                .of_match_table = ahci_of_match,
+               .acpi_match_table = ahci_acpi_match,
                .pm = &ahci_pm_ops,
        },
 };
index e83fc3d0da9c9c60a99a6dec56cc568a97a0a851..19bcb80b20313932021b1ee613eed97f4473e17e 100644 (file)
@@ -694,11 +694,11 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
  *     RETURNS:
  *     Block address read from @tf.
  */
-u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
+u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
 {
        u64 block = 0;
 
-       if (!dev || tf->flags & ATA_TFLAG_LBA) {
+       if (tf->flags & ATA_TFLAG_LBA) {
                if (tf->flags & ATA_TFLAG_LBA48) {
                        block |= (u64)tf->hob_lbah << 40;
                        block |= (u64)tf->hob_lbam << 32;
@@ -2147,24 +2147,6 @@ static int ata_dev_config_ncq(struct ata_device *dev,
        return 0;
 }
 
-static void ata_dev_config_sense_reporting(struct ata_device *dev)
-{
-       unsigned int err_mask;
-
-       if (!ata_id_has_sense_reporting(dev->id))
-               return;
-
-       if (ata_id_sense_reporting_enabled(dev->id))
-               return;
-
-       err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1);
-       if (err_mask) {
-               ata_dev_dbg(dev,
-                           "failed to enable Sense Data Reporting, Emask 0x%x\n",
-                           err_mask);
-       }
-}
-
 /**
  *     ata_dev_configure - Configure the specified ATA/ATAPI device
  *     @dev: Target device to configure
@@ -2387,7 +2369,7 @@ int ata_dev_configure(struct ata_device *dev)
                                        dev->devslp_timing[i] = sata_setting[j];
                                }
                }
-               ata_dev_config_sense_reporting(dev);
+
                dev->cdb_len = 16;
        }
 
@@ -2478,6 +2460,10 @@ int ata_dev_configure(struct ata_device *dev)
                dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
                                         dev->max_sectors);
 
+       if (dev->horkage & ATA_HORKAGE_MAX_SEC_1024)
+               dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024,
+                                        dev->max_sectors);
+
        if (dev->horkage & ATA_HORKAGE_MAX_SEC_LBA48)
                dev->max_sectors = ATA_MAX_SECTORS_LBA48;
 
@@ -4146,6 +4132,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Slimtype DVD A  DS8A8SH", NULL,      ATA_HORKAGE_MAX_SEC_LBA48 },
        { "Slimtype DVD A  DS8A9SH", NULL,      ATA_HORKAGE_MAX_SEC_LBA48 },
 
+       /*
+        * Causes silent data corruption with higher max sects.
+        * http://lkml.kernel.org/g/x49wpy40ysk.fsf@segfault.boston.devel.redhat.com
+        */
+       { "ST380013AS",         "3.20",         ATA_HORKAGE_MAX_SEC_1024 },
+
        /* Devices we expect to fail diagnostics */
 
        /* Devices where NCQ should be avoided */
@@ -4174,9 +4166,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "ST3320[68]13AS",     "SD1[5-9]",     ATA_HORKAGE_NONCQ |
                                                ATA_HORKAGE_FIRMWARE_WARN },
 
-       /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
+       /* drives which fail FPDMA_AA activation (some may freeze afterwards) */
        { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
        { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+       { "VB0250EAVER",        "HPG7",         ATA_HORKAGE_BROKEN_FPDMA_AA },
 
        /* Blacklist entries taken from Silicon Image 3124/3132
           Windows driver .inf file - also several Linux problem reports */
@@ -4229,7 +4222,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Crucial_CT*M500*",           NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
-       { "Micron_M5[15]0*",            "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+       { "Micron_M5[15]0_*",           "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Crucial_CT*M550*",           "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -4238,6 +4231,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Samsung SSD 8*",             NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
 
+       /* devices that don't properly handle TRIM commands */
+       { "SuperSSpeed S238*",          NULL,   ATA_HORKAGE_NOTRIM, },
+
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
         * (Return Zero After Trim) flags in the ATA Command Set are
@@ -4501,7 +4497,8 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
        else /* In the ancient relic department - skip all of this */
                return 0;
 
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       /* On some disks, this command causes spin-up, so we need longer timeout */
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 15000);
 
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
index 7465031a893c60c9e61f2c911abf218b39c81d2e..cb0508af1459ac43f4aa26f1a16d94134bd9d0bc 100644 (file)
@@ -1592,8 +1592,6 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
        tf->hob_lbah = buf[10];
        tf->nsect = buf[12];
        tf->hob_nsect = buf[13];
-       if (ata_id_has_ncq_autosense(dev->id))
-               tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
 
        return 0;
 }
@@ -1629,70 +1627,6 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
        return err_mask;
 }
 
-/**
- *     ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
- *     @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
- *     @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
- *     @dfl_sense_key: default sense key to use
- *
- *     Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
- *     SENSE.  This function is EH helper.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep).
- *
- *     RETURNS:
- *     encoded sense data on success, 0 on failure or if sense data
- *     is not available.
- */
-static u32 ata_eh_request_sense(struct ata_queued_cmd *qc,
-                               struct scsi_cmnd *cmd)
-{
-       struct ata_device *dev = qc->dev;
-       struct ata_taskfile tf;
-       unsigned int err_mask;
-
-       if (!cmd)
-               return 0;
-
-       DPRINTK("ATA request sense\n");
-       ata_dev_warn(dev, "request sense\n");
-       if (!ata_id_sense_reporting_enabled(dev->id)) {
-               ata_dev_warn(qc->dev, "sense data reporting disabled\n");
-               return 0;
-       }
-       ata_tf_init(dev, &tf);
-
-       tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-       tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
-       tf.command = ATA_CMD_REQ_SENSE_DATA;
-       tf.protocol = ATA_PROT_NODATA;
-
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
-       /*
-        * ACS-4 states:
-        * The device may set the SENSE DATA AVAILABLE bit to one in the
-        * STATUS field and clear the ERROR bit to zero in the STATUS field
-        * to indicate that the command returned completion without an error
-        * and the sense data described in table 306 is available.
-        *
-        * IOW the 'ATA_SENSE' bit might not be set even though valid
-        * sense data is available.
-        * So check for both.
-        */
-       if ((tf.command & ATA_SENSE) ||
-               tf.lbah != 0 || tf.lbam != 0 || tf.lbal != 0) {
-               ata_scsi_set_sense(cmd, tf.lbah, tf.lbam, tf.lbal);
-               qc->flags |= ATA_QCFLAG_SENSE_VALID;
-               ata_dev_warn(dev, "sense data %02x/%02x/%02x\n",
-                            tf.lbah, tf.lbam, tf.lbal);
-       } else {
-               ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
-                            tf.command, err_mask);
-       }
-       return err_mask;
-}
-
 /**
  *     atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *     @dev: device to perform REQUEST_SENSE to
@@ -1855,19 +1789,6 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
        memcpy(&qc->result_tf, &tf, sizeof(tf));
        qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
        qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
-       if (qc->result_tf.auxiliary) {
-               char sense_key, asc, ascq;
-
-               sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
-               asc = (qc->result_tf.auxiliary >> 8) & 0xff;
-               ascq = qc->result_tf.auxiliary & 0xff;
-               ata_dev_dbg(dev, "NCQ Autosense %02x/%02x/%02x\n",
-                           sense_key, asc, ascq);
-               ata_scsi_set_sense(qc->scsicmd, sense_key, asc, ascq);
-               ata_scsi_set_sense_information(qc->scsicmd, &qc->result_tf);
-               qc->flags |= ATA_QCFLAG_SENSE_VALID;
-       }
-
        ehc->i.err_mask &= ~AC_ERR_DEV;
 }
 
@@ -1897,27 +1818,6 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
                return ATA_EH_RESET;
        }
 
-       /*
-        * Sense data reporting does not work if the
-        * device fault bit is set.
-        */
-       if ((stat & ATA_SENSE) && !(stat & ATA_DF) &&
-           !(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
-               if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
-                       tmp = ata_eh_request_sense(qc, qc->scsicmd);
-                       if (tmp)
-                               qc->err_mask |= tmp;
-                       else
-                               ata_scsi_set_sense_information(qc->scsicmd, tf);
-               } else {
-                       ata_dev_warn(qc->dev, "sense data available but port frozen\n");
-               }
-       }
-
-       /* Set by NCQ autosense or request sense above */
-       if (qc->flags & ATA_QCFLAG_SENSE_VALID)
-               return 0;
-
        if (stat & (ATA_ERR | ATA_DF))
                qc->err_mask |= AC_ERR_DEV;
        else
@@ -2661,15 +2561,14 @@ static void ata_eh_link_report(struct ata_link *link)
 
 #ifdef CONFIG_ATA_VERBOSE_ERROR
                if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
-                                   ATA_SENSE | ATA_ERR)) {
+                                   ATA_ERR)) {
                        if (res->command & ATA_BUSY)
                                ata_dev_err(qc->dev, "status: { Busy }\n");
                        else
-                               ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n",
+                               ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
                                  res->command & ATA_DRDY ? "DRDY " : "",
                                  res->command & ATA_DF ? "DF " : "",
                                  res->command & ATA_DRQ ? "DRQ " : "",
-                                 res->command & ATA_SENSE ? "SENSE " : "",
                                  res->command & ATA_ERR ? "ERR " : "");
                }
 
index 7ccc084bf1dfb8f7b979f5e7ae777e030303d1b8..85aa76116a305eb50d77f2544c87f09914998bed 100644 (file)
@@ -460,6 +460,13 @@ static void sata_pmp_quirks(struct ata_port *ap)
                                       ATA_LFLAG_NO_SRST |
                                       ATA_LFLAG_ASSUME_ATA;
                }
+       } else if (vendor == 0x11ab && devid == 0x4140) {
+               /* Marvell 4140 quirks */
+               ata_for_each_link(link, ap, EDGE) {
+                       /* port 4 is for SEMB device and it doesn't like SRST */
+                       if (link->pmp == 4)
+                               link->flags |= ATA_LFLAG_DISABLED;
+               }
        }
 }
 
index 3131adcc1f87e001f7f8bfe317e92527665e4dd4..0d7f0da3a26929622080f94a2a3125c63676999e 100644 (file)
@@ -270,28 +270,13 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
            ata_scsi_park_show, ata_scsi_park_store);
 EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
 
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
 {
-       if (!cmd)
-               return;
-
        cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
 
        scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
 }
 
-void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
-                                   const struct ata_taskfile *tf)
-{
-       u64 information;
-
-       if (!cmd)
-               return;
-
-       information = ata_tf_read_block(tf, NULL);
-       scsi_set_sense_information(cmd->sense_buffer, information);
-}
-
 static ssize_t
 ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
@@ -1792,9 +1777,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
            ((cdb[2] & 0x20) || need_sense)) {
                ata_gen_passthru_sense(qc);
        } else {
-               if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
-                       cmd->result = SAM_STAT_CHECK_CONDITION;
-               } else if (!need_sense) {
+               if (!need_sense) {
                        cmd->result = SAM_STAT_GOOD;
                } else {
                        /* TODO: decide which descriptor format to use
@@ -2568,7 +2551,8 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
                rbuf[14] = (lowest_aligned >> 8) & 0x3f;
                rbuf[15] = lowest_aligned;
 
-               if (ata_id_has_trim(args->id)) {
+               if (ata_id_has_trim(args->id) &&
+                   !(dev->horkage & ATA_HORKAGE_NOTRIM)) {
                        rbuf[14] |= 0x80; /* LBPME */
 
                        if (ata_id_has_zero_after_trim(args->id) &&
index d6c37bcd416d17145f291136b6e5f2a7192ee404..e2d94972962d69d766e99e8ade594040ae8d9429 100644 (file)
@@ -569,6 +569,8 @@ show_ata_dev_trim(struct device *dev,
 
        if (!ata_id_has_trim(ata_dev->id))
                mode = "unsupported";
+       else if (ata_dev->horkage & ATA_HORKAGE_NOTRIM)
+               mode = "forced_unsupported";
        else if (ata_dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM)
                        mode = "forced_unqueued";
        else if (ata_fpdma_dsm_supported(ata_dev))
index a998a175f9f144b50e4df782bbf7d1afd5f506cb..f840ca18a7c014f5151d22e4bc55dff9fca459de 100644 (file)
@@ -67,8 +67,7 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
 extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
                           u64 block, u32 n_block, unsigned int tf_flags,
                           unsigned int tag);
-extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
-                            struct ata_device *dev);
+extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
 extern unsigned ata_exec_internal(struct ata_device *dev,
                                  struct ata_taskfile *tf, const u8 *cdb,
                                  int dma_dir, void *buf, unsigned int buflen,
@@ -138,9 +137,6 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
                              struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq);
-extern void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
-                                          const struct ata_taskfile *tf);
 extern void ata_scsi_media_change_notify(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
index a9b0c820f2ebc7028cb933b7b021e42b3c6a7930..5d9ee99c21481eac524415091e57da0370fa7a64 100644 (file)
@@ -4,7 +4,7 @@
  * Arasan Compact Flash host controller source file
  *
  * Copyright (C) 2011 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -968,7 +968,7 @@ static struct platform_driver arasan_cf_driver = {
 
 module_platform_driver(arasan_cf_driver);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("Arasan ATA Compact Flash driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRIVER_NAME);
index 3a18a8a719b4ff1fa562a515b4701da241e4aeb7..fab504fd9cfd7ace54d772927a01650373d02206 100644 (file)
@@ -1238,8 +1238,12 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
        readl(mmio + PDC_SDRAM_CONTROL);
 
        /* Turn on for ECC */
-       pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
-                         PDC_DIMM_SPD_TYPE, &spd0);
+       if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
+                              PDC_DIMM_SPD_TYPE, &spd0)) {
+               pr_err("Failed in i2c read: device=%#x, subaddr=%#x\n",
+                      PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
+               return 1;
+       }
        if (spd0 == 0x02) {
                data |= (0x01 << 16);
                writel(data, mmio + PDC_SDRAM_CONTROL);
@@ -1380,8 +1384,12 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
 
        /* ECC initiliazation. */
 
-       pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
-                         PDC_DIMM_SPD_TYPE, &spd0);
+       if (!pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
+                              PDC_DIMM_SPD_TYPE, &spd0)) {
+               pr_err("Failed in i2c read: device=%#x, subaddr=%#x\n",
+                      PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE);
+               return 1;
+       }
        if (spd0 == 0x02) {
                void *buf;
                VPRINTK("Start ECC initialization\n");
index 9c4288362a8eaab0825d489c6362ceb573cbad30..894bda114224d667077c25c898025b1af83c590a 100644 (file)
@@ -563,10 +563,8 @@ static void fw_dev_release(struct device *dev)
        kfree(fw_priv);
 }
 
-static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env)
 {
-       struct firmware_priv *fw_priv = to_firmware_priv(dev);
-
        if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id))
                return -ENOMEM;
        if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
@@ -577,6 +575,18 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct firmware_priv *fw_priv = to_firmware_priv(dev);
+       int err = 0;
+
+       mutex_lock(&fw_lock);
+       if (fw_priv->buf)
+               err = do_firmware_uevent(fw_priv, env);
+       mutex_unlock(&fw_lock);
+       return err;
+}
+
 static struct class firmware_class = {
        .name           = "firmware",
        .class_attrs    = firmware_class_attrs,
index cdd547bd67df82184dd201b4e1cf9626cf90dd2e..0ee43c1056e045bd6a402908e8a11cf9dac8f34e 100644 (file)
@@ -6,6 +6,7 @@
  * This file is released under the GPLv2.
  */
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
@@ -19,6 +20,8 @@
 #include <linux/suspend.h>
 #include <linux/export.h>
 
+#define GENPD_RETRY_MAX_MS     250             /* Approximate */
+
 #define GENPD_DEV_CALLBACK(genpd, type, callback, dev)         \
 ({                                                             \
        type (*__routine)(struct device *__d);                  \
@@ -2131,6 +2134,7 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
 static void genpd_dev_pm_detach(struct device *dev, bool power_off)
 {
        struct generic_pm_domain *pd;
+       unsigned int i;
        int ret = 0;
 
        pd = pm_genpd_lookup_dev(dev);
@@ -2139,10 +2143,12 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
 
        dev_dbg(dev, "removing from PM domain %s\n", pd->name);
 
-       while (1) {
+       for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
                ret = pm_genpd_remove_device(pd, dev);
                if (ret != -EAGAIN)
                        break;
+
+               mdelay(i);
                cond_resched();
        }
 
@@ -2183,6 +2189,7 @@ int genpd_dev_pm_attach(struct device *dev)
 {
        struct of_phandle_args pd_args;
        struct generic_pm_domain *pd;
+       unsigned int i;
        int ret;
 
        if (!dev->of_node)
@@ -2218,10 +2225,12 @@ int genpd_dev_pm_attach(struct device *dev)
 
        dev_dbg(dev, "adding to PM domain %s\n", pd->name);
 
-       while (1) {
+       for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
                ret = pm_genpd_add_device(pd, dev);
                if (ret != -EAGAIN)
                        break;
+
+               mdelay(i);
                cond_resched();
        }
 
index 7470004ca8105d5e28c48563a0c683c0466915c0..eb6e67451decee999901493d9182ed6c9cf21bf9 100644 (file)
@@ -45,14 +45,12 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq,
                return -EEXIST;
        }
 
-       dev->power.wakeirq = wirq;
-       spin_unlock_irqrestore(&dev->power.lock, flags);
-
        err = device_wakeup_attach_irq(dev, wirq);
-       if (err)
-               return err;
+       if (!err)
+               dev->power.wakeirq = wirq;
 
-       return 0;
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+       return err;
 }
 
 /**
@@ -105,10 +103,10 @@ void dev_pm_clear_wake_irq(struct device *dev)
                return;
 
        spin_lock_irqsave(&dev->power.lock, flags);
+       device_wakeup_detach_irq(dev);
        dev->power.wakeirq = NULL;
        spin_unlock_irqrestore(&dev->power.lock, flags);
 
-       device_wakeup_detach_irq(dev);
        if (wirq->dedicated_irq)
                free_irq(wirq->irq, wirq);
        kfree(wirq);
index 40f71603378cb5872265c9df994e6ca8cb756ffc..51f15bc15774250a203b46c44b5682b36f450f1d 100644 (file)
@@ -281,32 +281,25 @@ EXPORT_SYMBOL_GPL(device_wakeup_enable);
  * Attach a device wakeirq to the wakeup source so the device
  * wake IRQ can be configured automatically for suspend and
  * resume.
+ *
+ * Call under the device's power.lock lock.
  */
 int device_wakeup_attach_irq(struct device *dev,
                             struct wake_irq *wakeirq)
 {
        struct wakeup_source *ws;
-       int ret = 0;
 
-       spin_lock_irq(&dev->power.lock);
        ws = dev->power.wakeup;
        if (!ws) {
                dev_err(dev, "forgot to call call device_init_wakeup?\n");
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
-       if (ws->wakeirq) {
-               ret = -EEXIST;
-               goto unlock;
-       }
+       if (ws->wakeirq)
+               return -EEXIST;
 
        ws->wakeirq = wakeirq;
-
-unlock:
-       spin_unlock_irq(&dev->power.lock);
-
-       return ret;
+       return 0;
 }
 
 /**
@@ -314,20 +307,16 @@ unlock:
  * @dev: Device to handle
  *
  * Removes a device wakeirq from the wakeup source.
+ *
+ * Call under the device's power.lock lock.
  */
 void device_wakeup_detach_irq(struct device *dev)
 {
        struct wakeup_source *ws;
 
-       spin_lock_irq(&dev->power.lock);
        ws = dev->power.wakeup;
-       if (!ws)
-               goto unlock;
-
-       ws->wakeirq = NULL;
-
-unlock:
-       spin_unlock_irq(&dev->power.lock);
+       if (ws)
+               ws->wakeirq = NULL;
 }
 
 /**
index 81751a49d8bf2334612350bba52406b9af352258..56486d92c4e72bd583630baea0fba541f36c926f 100644 (file)
@@ -296,11 +296,20 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        if (!blk)
                return -ENOMEM;
 
-       present = krealloc(rbnode->cache_present,
-                   BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL);
-       if (!present) {
-               kfree(blk);
-               return -ENOMEM;
+       if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
+               present = krealloc(rbnode->cache_present,
+                                  BITS_TO_LONGS(blklen) * sizeof(*present),
+                                  GFP_KERNEL);
+               if (!present) {
+                       kfree(blk);
+                       return -ENOMEM;
+               }
+
+               memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
+                      (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
+                      * sizeof(*present));
+       } else {
+               present = rbnode->cache_present;
        }
 
        /* insert the register value in the correct place in the rbnode block */
index 69de41a87b74311b2b7478fb0226b8bc253c6ebc..3177b245d2bdf63e821a12a4c0f18cbab1b16229 100644 (file)
@@ -240,19 +240,19 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
        while ((entry = llist_del_all(&cq->list)) != NULL) {
                entry = llist_reverse_order(entry);
                do {
+                       struct request_queue *q = NULL;
+
                        cmd = container_of(entry, struct nullb_cmd, ll_list);
                        entry = entry->next;
+                       if (cmd->rq)
+                               q = cmd->rq->q;
                        end_cmd(cmd);
 
-                       if (cmd->rq) {
-                               struct request_queue *q = cmd->rq->q;
-
-                               if (!q->mq_ops && blk_queue_stopped(q)) {
-                                       spin_lock(q->queue_lock);
-                                       if (blk_queue_stopped(q))
-                                               blk_start_queue(q);
-                                       spin_unlock(q->queue_lock);
-                               }
+                       if (q && !q->mq_ops && blk_queue_stopped(q)) {
+                               spin_lock(q->queue_lock);
+                               if (blk_queue_stopped(q))
+                                       blk_start_queue(q);
+                               spin_unlock(q->queue_lock);
                        }
                } while (entry);
        }
index d1d6141920d3ced742d850b051d273d65aa3728e..7920c2741b47d436b2ef37e99019f33938f2db04 100644 (file)
@@ -2108,8 +2108,17 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
                goto out_free_disk;
 
        add_disk(ns->disk);
-       if (ns->ms)
-               revalidate_disk(ns->disk);
+       if (ns->ms) {
+               struct block_device *bd = bdget_disk(ns->disk, 0);
+               if (!bd)
+                       return;
+               if (blkdev_get(bd, FMODE_READ, NULL)) {
+                       bdput(bd);
+                       return;
+               }
+               blkdev_reread_part(bd);
+               blkdev_put(bd, FMODE_READ);
+       }
        return;
  out_free_disk:
        kfree(disk);
index d94529d5c8e951378eaf62d74b708edf271a550f..bc67a93aa4f4749f10d1a219789b21661c01ee21 100644 (file)
@@ -523,6 +523,7 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
 #  define rbd_assert(expr)     ((void) 0)
 #endif /* !RBD_DEBUG */
 
+static void rbd_osd_copyup_callback(struct rbd_obj_request *obj_request);
 static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request);
 static void rbd_img_parent_read(struct rbd_obj_request *obj_request);
 static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
@@ -1818,6 +1819,16 @@ static void rbd_osd_stat_callback(struct rbd_obj_request *obj_request)
        obj_request_done_set(obj_request);
 }
 
+static void rbd_osd_call_callback(struct rbd_obj_request *obj_request)
+{
+       dout("%s: obj %p\n", __func__, obj_request);
+
+       if (obj_request_img_data_test(obj_request))
+               rbd_osd_copyup_callback(obj_request);
+       else
+               obj_request_done_set(obj_request);
+}
+
 static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
                                struct ceph_msg *msg)
 {
@@ -1866,6 +1877,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
                rbd_osd_discard_callback(obj_request);
                break;
        case CEPH_OSD_OP_CALL:
+               rbd_osd_call_callback(obj_request);
+               break;
        case CEPH_OSD_OP_NOTIFY_ACK:
        case CEPH_OSD_OP_WATCH:
                rbd_osd_trivial_callback(obj_request);
@@ -2530,13 +2543,15 @@ out_unwind:
 }
 
 static void
-rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
+rbd_osd_copyup_callback(struct rbd_obj_request *obj_request)
 {
        struct rbd_img_request *img_request;
        struct rbd_device *rbd_dev;
        struct page **pages;
        u32 page_count;
 
+       dout("%s: obj %p\n", __func__, obj_request);
+
        rbd_assert(obj_request->type == OBJ_REQUEST_BIO ||
                obj_request->type == OBJ_REQUEST_NODATA);
        rbd_assert(obj_request_img_data_test(obj_request));
@@ -2563,9 +2578,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
        if (!obj_request->result)
                obj_request->xferred = obj_request->length;
 
-       /* Finish up with the normal image object callback */
-
-       rbd_img_obj_callback(obj_request);
+       obj_request_done_set(obj_request);
 }
 
 static void
@@ -2650,7 +2663,6 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
 
        /* All set, send it off. */
 
-       orig_request->callback = rbd_img_obj_copyup_callback;
        osdc = &rbd_dev->rbd_client->client->osdc;
        img_result = rbd_obj_request_submit(osdc, orig_request);
        if (!img_result)
index ced96777b677b9bcddd65bae004a7a51b5cf0dc3..954c0029fb3babc49d1a1f490f9d420934701e30 100644 (file)
@@ -369,8 +369,8 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
                return;
        }
 
-       if (work_pending(&blkif->persistent_purge_work)) {
-               pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n");
+       if (work_busy(&blkif->persistent_purge_work)) {
+               pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
                return;
        }
 
index 6d89ed35d80c0caaf8bf57ba82c7e9f3a9194bb9..7a8a73f1fc0462feab5bad706573ff6eb4536ef7 100644 (file)
@@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock);
        ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
 
 static int blkfront_setup_indirect(struct blkfront_info *info);
+static int blkfront_gather_backend_features(struct blkfront_info *info);
 
 static int get_id_from_freelist(struct blkfront_info *info)
 {
@@ -1128,8 +1129,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                                 * Add the used indirect page back to the list of
                                 * available pages for indirect grefs.
                                 */
-                               indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
-                               list_add(&indirect_page->lru, &info->indirect_pages);
+                               if (!info->feature_persistent) {
+                                       indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
+                                       list_add(&indirect_page->lru, &info->indirect_pages);
+                               }
                                s->indirect_grants[i]->gref = GRANT_INVALID_REF;
                                list_add_tail(&s->indirect_grants[i]->node, &info->grants);
                        }
@@ -1519,7 +1522,7 @@ static int blkif_recover(struct blkfront_info *info)
        info->shadow_free = info->ring.req_prod_pvt;
        info->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff;
 
-       rc = blkfront_setup_indirect(info);
+       rc = blkfront_gather_backend_features(info);
        if (rc) {
                kfree(copy);
                return rc;
@@ -1720,20 +1723,13 @@ static void blkfront_setup_discard(struct blkfront_info *info)
 
 static int blkfront_setup_indirect(struct blkfront_info *info)
 {
-       unsigned int indirect_segments, segs;
+       unsigned int segs;
        int err, i;
 
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-max-indirect-segments", "%u", &indirect_segments,
-                           NULL);
-       if (err) {
-               info->max_indirect_segments = 0;
+       if (info->max_indirect_segments == 0)
                segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-       } else {
-               info->max_indirect_segments = min(indirect_segments,
-                                                 xen_blkif_max_segments);
+       else
                segs = info->max_indirect_segments;
-       }
 
        err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info));
        if (err)
@@ -1796,6 +1792,68 @@ out_of_memory:
        return -ENOMEM;
 }
 
+/*
+ * Gather all backend feature-*
+ */
+static int blkfront_gather_backend_features(struct blkfront_info *info)
+{
+       int err;
+       int barrier, flush, discard, persistent;
+       unsigned int indirect_segments;
+
+       info->feature_flush = 0;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-barrier", "%d", &barrier,
+                       NULL);
+
+       /*
+        * If there's no "feature-barrier" defined, then it means
+        * we're dealing with a very old backend which writes
+        * synchronously; nothing to do.
+        *
+        * If there are barriers, then we use flush.
+        */
+       if (!err && barrier)
+               info->feature_flush = REQ_FLUSH | REQ_FUA;
+       /*
+        * And if there is "feature-flush-cache" use that above
+        * barriers.
+        */
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-flush-cache", "%d", &flush,
+                       NULL);
+
+       if (!err && flush)
+               info->feature_flush = REQ_FLUSH;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-discard", "%d", &discard,
+                       NULL);
+
+       if (!err && discard)
+               blkfront_setup_discard(info);
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "feature-persistent", "%u", &persistent,
+                       NULL);
+       if (err)
+               info->feature_persistent = 0;
+       else
+               info->feature_persistent = persistent;
+
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-max-indirect-segments", "%u", &indirect_segments,
+                           NULL);
+       if (err)
+               info->max_indirect_segments = 0;
+       else
+               info->max_indirect_segments = min(indirect_segments,
+                                                 xen_blkif_max_segments);
+
+       return blkfront_setup_indirect(info);
+}
+
 /*
  * Invoked when the backend is finally 'ready' (and has told produced
  * the details about the physical device - #sectors, size, etc).
@@ -1807,7 +1865,6 @@ static void blkfront_connect(struct blkfront_info *info)
        unsigned int physical_sector_size;
        unsigned int binfo;
        int err;
-       int barrier, flush, discard, persistent;
 
        switch (info->connected) {
        case BLKIF_STATE_CONNECTED:
@@ -1864,48 +1921,7 @@ static void blkfront_connect(struct blkfront_info *info)
        if (err != 1)
                physical_sector_size = sector_size;
 
-       info->feature_flush = 0;
-
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-barrier", "%d", &barrier,
-                           NULL);
-
-       /*
-        * If there's no "feature-barrier" defined, then it means
-        * we're dealing with a very old backend which writes
-        * synchronously; nothing to do.
-        *
-        * If there are barriers, then we use flush.
-        */
-       if (!err && barrier)
-               info->feature_flush = REQ_FLUSH | REQ_FUA;
-       /*
-        * And if there is "feature-flush-cache" use that above
-        * barriers.
-        */
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-flush-cache", "%d", &flush,
-                           NULL);
-
-       if (!err && flush)
-               info->feature_flush = REQ_FLUSH;
-
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-discard", "%d", &discard,
-                           NULL);
-
-       if (!err && discard)
-               blkfront_setup_discard(info);
-
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-persistent", "%u", &persistent,
-                           NULL);
-       if (err)
-               info->feature_persistent = 0;
-       else
-               info->feature_persistent = persistent;
-
-       err = blkfront_setup_indirect(info);
+       err = blkfront_gather_backend_features(info);
        if (err) {
                xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
                                 info->xbdev->otherend);
index fb655e8d1e3b17bf4cda9fd09593bc7dc770f78d..763301c7828c72650f2abaa1c723425bdd3c73f4 100644 (file)
@@ -496,10 +496,9 @@ static void zram_meta_free(struct zram_meta *meta, u64 disksize)
        kfree(meta);
 }
 
-static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
+static struct zram_meta *zram_meta_alloc(char *pool_name, u64 disksize)
 {
        size_t num_pages;
-       char pool_name[8];
        struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
 
        if (!meta)
@@ -512,7 +511,6 @@ static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
                goto out_error;
        }
 
-       snprintf(pool_name, sizeof(pool_name), "zram%d", device_id);
        meta->mem_pool = zs_create_pool(pool_name, GFP_NOIO | __GFP_HIGHMEM);
        if (!meta->mem_pool) {
                pr_err("Error creating memory pool\n");
@@ -1031,7 +1029,7 @@ static ssize_t disksize_store(struct device *dev,
                return -EINVAL;
 
        disksize = PAGE_ALIGN(disksize);
-       meta = zram_meta_alloc(zram->disk->first_minor, disksize);
+       meta = zram_meta_alloc(zram->disk->disk_name, disksize);
        if (!meta)
                return -ENOMEM;
 
index 1e1a4323a71fd304d410e421b488758d2300b34d..9ceb8ac68fdca2518c953cb6a9a36c6fd5b5f268 100644 (file)
@@ -472,12 +472,11 @@ int btbcm_setup_apple(struct hci_dev *hdev)
 
        /* Read Verbose Config Version Info */
        skb = btbcm_read_verbose_config(hdev);
-       if (IS_ERR(skb))
-               return PTR_ERR(skb);
-
-       BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
-               get_unaligned_le16(skb->data + 5));
-       kfree_skb(skb);
+       if (!IS_ERR(skb)) {
+               BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
+                       get_unaligned_le16(skb->data + 5));
+               kfree_skb(skb);
+       }
 
        set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
 
index da8faf78536a3ae01827a2ee9480c486a04297a5..5643b65cee204d950d842529e0a12123f57e92c0 100644 (file)
@@ -429,7 +429,7 @@ static int hwrng_fillfn(void *unused)
 static void start_khwrngd(void)
 {
        hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
-       if (hwrng_fill == ERR_PTR(-ENOMEM)) {
+       if (IS_ERR(hwrng_fill)) {
                pr_err("hwrng_fill thread creation failed");
                hwrng_fill = NULL;
        }
index 283f00a7f03629c12f8294e2aee67e1e598acf4d..1082d4bb016a9e4d7caf795a5128509780134916 100644 (file)
@@ -129,8 +129,9 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 
        device_initialize(&chip->dev);
 
-       chip->cdev.owner = chip->pdev->driver->owner;
        cdev_init(&chip->cdev, &tpm_fops);
+       chip->cdev.owner = chip->pdev->driver->owner;
+       chip->cdev.kobj.parent = &chip->dev.kobj;
 
        return chip;
 }
index 44f9d20c19ac6e7724b66fae3329ae7111c8e61e..1267322595da0ec0a53bd10a8ba93531a036f483 100644 (file)
@@ -233,6 +233,14 @@ static int crb_acpi_add(struct acpi_device *device)
                return -ENODEV;
        }
 
+       /* At least some versions of AMI BIOS have a bug that TPM2 table has
+        * zero address for the control area and therefore we must fail.
+       */
+       if (!buf->control_area_pa) {
+               dev_err(dev, "TPM2 ACPI table has a zero address for the control area\n");
+               return -EINVAL;
+       }
+
        if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
                dev_err(dev, "TPM2 ACPI table has wrong size");
                return -EINVAL;
index 152dcb3f7b5f50c9897f571885029f487c6fcdf0..61566bcefa53399ab3af07611398af3f114849c7 100644 (file)
@@ -116,8 +116,10 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
        h32mxclk->pmc = pmc;
 
        clk = clk_register(NULL, &h32mxclk->hw);
-       if (!clk)
+       if (!clk) {
+               kfree(h32mxclk);
                return;
+       }
 
        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
index c2400456a04471186ec210d8236951d9e4780901..27dfa965cfedb020ebf66b635e0053ca58cefc1c 100644 (file)
@@ -171,8 +171,10 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
        irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
        ret = request_irq(osc->irq, clk_main_osc_irq_handler,
                          IRQF_TRIGGER_HIGH, name, osc);
-       if (ret)
+       if (ret) {
+               kfree(osc);
                return ERR_PTR(ret);
+       }
 
        if (bypass)
                pmc_write(pmc, AT91_CKGR_MOR,
index f98eafe9b12dc92d1c68f99cd5d9cc86addfb75f..5b3ded5205a29177dde69509bd72032f7fff61aa 100644 (file)
@@ -165,12 +165,16 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
        irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
        ret = request_irq(master->irq, clk_master_irq_handler,
                          IRQF_TRIGGER_HIGH, "clk-master", master);
-       if (ret)
+       if (ret) {
+               kfree(master);
                return ERR_PTR(ret);
+       }
 
        clk = clk_register(NULL, &master->hw);
-       if (IS_ERR(clk))
+       if (IS_ERR(clk)) {
+               free_irq(master->irq, master);
                kfree(master);
+       }
 
        return clk;
 }
index cbbe40377ad622a7f9d38aca5651916dda549e54..18b60f4895a68477a74ebe99a8b64542bd7057c9 100644 (file)
@@ -346,12 +346,16 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
        irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
        ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
                          id ? "clk-pllb" : "clk-plla", pll);
-       if (ret)
+       if (ret) {
+               kfree(pll);
                return ERR_PTR(ret);
+       }
 
        clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk))
+       if (IS_ERR(clk)) {
+               free_irq(pll->irq, pll);
                kfree(pll);
+       }
 
        return clk;
 }
index a76d03fd577be05fe86a95d51092380ab01e4eb1..58008b3e8bc175f8befb8126e99e5f55c57d2176 100644 (file)
@@ -130,13 +130,17 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
                irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
                ret = request_irq(sys->irq, clk_system_irq_handler,
                                IRQF_TRIGGER_HIGH, name, sys);
-               if (ret)
+               if (ret) {
+                       kfree(sys);
                        return ERR_PTR(ret);
+               }
        }
 
        clk = clk_register(NULL, &sys->hw);
-       if (IS_ERR(clk))
+       if (IS_ERR(clk)) {
+               free_irq(sys->irq, sys);
                kfree(sys);
+       }
 
        return clk;
 }
index ae3263bc14765042d035bea91a476b45655aae75..30dd697b1668bea6d437655d5c7fc825cda3f52a 100644 (file)
@@ -118,12 +118,16 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
        irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
        ret = request_irq(utmi->irq, clk_utmi_irq_handler,
                          IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
-       if (ret)
+       if (ret) {
+               kfree(utmi);
                return ERR_PTR(ret);
+       }
 
        clk = clk_register(NULL, &utmi->hw);
-       if (IS_ERR(clk))
+       if (IS_ERR(clk)) {
+               free_irq(utmi->irq, utmi);
                kfree(utmi);
+       }
 
        return clk;
 }
index e19c09cd9645557602840576668fbbc4c18b099d..f630e1bbdcfee9ba2016c856ee7f3b9f449a0205 100644 (file)
@@ -222,10 +222,6 @@ void __init iproc_asiu_setup(struct device_node *node,
                struct iproc_asiu_clk *asiu_clk;
                const char *clk_name;
 
-               clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
-               if (WARN_ON(!clk_name))
-                       goto err_clk_register;
-
                ret = of_property_read_string_index(node, "clock-output-names",
                                                    i, &clk_name);
                if (WARN_ON(ret))
@@ -259,7 +255,7 @@ void __init iproc_asiu_setup(struct device_node *node,
 
 err_clk_register:
        for (i = 0; i < num_clks; i++)
-               kfree(asiu->clks[i].name);
+               clk_unregister(asiu->clk_data.clks[i]);
        iounmap(asiu->gate_base);
 
 err_iomap_gate:
index 46fb84bc26740dde1679d7015949977337418561..2dda4e8295a912a4ca28f091fc8a4af86f1c4662 100644 (file)
@@ -366,7 +366,7 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
        val = readl(pll->pll_base + ctrl->ndiv_int.offset);
        ndiv_int = (val >> ctrl->ndiv_int.shift) &
                bit_mask(ctrl->ndiv_int.width);
-       ndiv = ndiv_int << ctrl->ndiv_int.shift;
+       ndiv = (u64)ndiv_int << ctrl->ndiv_int.shift;
 
        if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
                val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
@@ -374,7 +374,8 @@ static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
                        bit_mask(ctrl->ndiv_frac.width);
 
                if (ndiv_frac != 0)
-                       ndiv = (ndiv_int << ctrl->ndiv_int.shift) | ndiv_frac;
+                       ndiv = ((u64)ndiv_int << ctrl->ndiv_int.shift) |
+                               ndiv_frac;
        }
 
        val = readl(pll->pll_base + ctrl->pdiv.offset);
@@ -655,10 +656,6 @@ void __init iproc_pll_clk_setup(struct device_node *node,
                memset(&init, 0, sizeof(init));
                parent_name = node->name;
 
-               clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
-               if (WARN_ON(!clk_name))
-                       goto err_clk_register;
-
                ret = of_property_read_string_index(node, "clock-output-names",
                                                    i, &clk_name);
                if (WARN_ON(ret))
@@ -690,10 +687,8 @@ void __init iproc_pll_clk_setup(struct device_node *node,
        return;
 
 err_clk_register:
-       for (i = 0; i < num_clks; i++) {
-               kfree(pll->clks[i].name);
+       for (i = 0; i < num_clks; i++)
                clk_unregister(pll->clk_data.clks[i]);
-       }
 
 err_pll_register:
        if (pll->asiu_base)
index b9b12a742970d5e195f048e571bd5cf7936694e6..3f6f7ad39490458a6e9cdcf4d944665abd34df86 100644 (file)
@@ -268,7 +268,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary)
        memcpy(table, stm32f42xx_gate_map, sizeof(table));
 
        /* only bits set in table can be used as indices */
-       if (WARN_ON(secondary > 8 * sizeof(table) ||
+       if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) ||
                    0 == (table[BIT_ULL_WORD(secondary)] &
                          BIT_ULL_MASK(secondary))))
                return -EINVAL;
index 4b9e04cdf7e8e5d7135351db855a8dcfac5e47fb..8b6523d15fb85984f5fb73304fa21803c40b730f 100644 (file)
@@ -700,6 +700,22 @@ static const struct mtk_composite peri_clks[] __initconst = {
        MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
 };
 
+static struct clk_onecell_data *mt8173_top_clk_data __initdata;
+static struct clk_onecell_data *mt8173_pll_clk_data __initdata;
+
+static void __init mtk_clk_enable_critical(void)
+{
+       if (!mt8173_top_clk_data || !mt8173_pll_clk_data)
+               return;
+
+       clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA15PLL]);
+       clk_prepare_enable(mt8173_pll_clk_data->clks[CLK_APMIXED_ARMCA7PLL]);
+       clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_MEM_SEL]);
+       clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
+       clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_CCI400_SEL]);
+       clk_prepare_enable(mt8173_top_clk_data->clks[CLK_TOP_RTC_SEL]);
+}
+
 static void __init mtk_topckgen_init(struct device_node *node)
 {
        struct clk_onecell_data *clk_data;
@@ -712,19 +728,19 @@ static void __init mtk_topckgen_init(struct device_node *node)
                return;
        }
 
-       clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+       mt8173_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
 
        mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
        mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
        mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
                        &mt8173_clk_lock, clk_data);
 
-       clk_prepare_enable(clk_data->clks[CLK_TOP_CCI400_SEL]);
-
        r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
        if (r)
                pr_err("%s(): could not register clock provider: %d\n",
                        __func__, r);
+
+       mtk_clk_enable_critical();
 }
 CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init);
 
@@ -818,13 +834,13 @@ static void __init mtk_apmixedsys_init(struct device_node *node)
 {
        struct clk_onecell_data *clk_data;
 
-       clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+       mt8173_pll_clk_data = clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
        if (!clk_data)
                return;
 
        mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
 
-       clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMCA15PLL]);
+       mtk_clk_enable_critical();
 }
 CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys",
                mtk_apmixedsys_init);
index 4b93a1efb36d11fa7171735d29bac283e4bb6d97..ac03ba49e9d1952dff14e9383ed86874690a7176 100644 (file)
@@ -126,7 +126,7 @@ PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
 PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
 PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
 
-#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENB : &CKENA)
 #define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
                    div_hp, bit, is_lp, flags)                          \
        PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp,         \
index b95d17fbb8d7edb86fa6754d21b47dc6d1e66ee6..92936f0912d2f86622d5ae1372cf03a046b83979 100644 (file)
@@ -530,19 +530,16 @@ static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
        struct clk_rcg2 *rcg = to_clk_rcg2(hw);
        struct freq_tbl f = *rcg->freq_tbl;
        const struct frac_entry *frac = frac_table_pixel;
-       unsigned long request, src_rate;
+       unsigned long request;
        int delta = 100000;
        u32 mask = BIT(rcg->hid_width) - 1;
        u32 hid_div;
-       int index = qcom_find_src_index(hw, rcg->parent_map, f.src);
-       struct clk *parent = clk_get_parent_by_index(hw->clk, index);
 
        for (; frac->num; frac++) {
                request = (rate * frac->den) / frac->num;
 
-               src_rate = __clk_round_rate(parent, request);
-               if ((src_rate < (request - delta)) ||
-                       (src_rate > (request + delta)))
+               if ((parent_rate < (request - delta)) ||
+                       (parent_rate > (request + delta)))
                        continue;
 
                regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
index bdfb4421c64365586b19b478c5288dd58c27f829..f271c350ef9404838fcaa6502db28cd1db5a744c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index dffd4ce6c8b5513e8dd4fdadcc06a68cc3a209fe..58d678b5b40a76c6e426b41ed957e044197b2ae8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 1afc18c4effcc150f6bda6dede54e134e9ab4d68..1a722e99e76e949352ab03120440ec3e312c365d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 1b9b65bca51edbf65ba6ba62d39d7520a19f7453..5ebddc528145bb82827c2a6895b5467fb6dfaeca 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 628b6d5ed3d96a35b799d55e2467f7970ea5384d..157fe099ea6ad6b7fb8904d390de41b53c982489 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 931737677dfab553032f8a720893c719c4f0a639..9834944f08b1dafff2a24835a5b1e57b010e3e4a 100644 (file)
@@ -2,7 +2,7 @@
  * Clock framework definitions for SPEAr platform
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 4daa5977793ae058803c178581c0dbdc2409b2e9..222ce108b41a0e48afd4bf2d370a535d24511774 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr1310 machine clock framework source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 5a5c6648308dbc6f8009e6d5702dce3d95572532..973c9d3fbcf82285e2a6bf6412cb15fe602a892e 100644 (file)
@@ -4,7 +4,7 @@
  * SPEAr1340 machine clock framework source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index bb5f387774e2ce364b0e660c5d22271282b77084..404a55edd613d102f00bda3e127f7125b07fed88 100644 (file)
@@ -2,7 +2,7 @@
  * SPEAr3xx machines clock framework source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 4f649c9cb094e2c9019cc5528d64819a632e0489..231061fa73a4309b0744d2a8dda0d68bddeda5e0 100644 (file)
@@ -2,7 +2,7 @@
  * SPEAr6xx machines clock framework source file
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 657ca14ba709a64b97e297e74f15f8f5d751efdf..8dd8cce273617e1db85c8af512a431cef14cf328 100644 (file)
@@ -190,7 +190,7 @@ static struct clk *clk_register_flexgen(const char *name,
 
        init.name = name;
        init.ops = &flexgen_ops;
-       init.flags = CLK_IS_BASIC | flexgen_flags;
+       init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE | flexgen_flags;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
 
@@ -303,6 +303,8 @@ static void __init st_of_flexgen_setup(struct device_node *np)
        if (!rlock)
                goto err;
 
+       spin_lock_init(rlock);
+
        for (i = 0; i < clk_data->clk_num; i++) {
                struct clk *clk;
                const char *clk_name;
index e94197f04b0b3bae5a811c70e7d91393a2a263c6..d9eb2e1d84710c34abe8b656b4dd5e89a1ac7f9a 100644 (file)
@@ -340,7 +340,7 @@ static const struct clkgen_quadfs_data st_fs660c32_C_407 = {
                    CLKGEN_FIELD(0x30c, 0xf, 20),
                    CLKGEN_FIELD(0x310, 0xf, 20) },
        .lockstatus_present = true,
-       .lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24),
+       .lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24),
        .powerup_polarity = 1,
        .standby_polarity = 1,
        .pll_ops        = &st_quadfs_pll_c32_ops,
@@ -489,7 +489,7 @@ static int quadfs_pll_is_enabled(struct clk_hw *hw)
        struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
        u32 npda = CLKGEN_READ(pll, npda);
 
-       return !!npda;
+       return pll->data->powerup_polarity ? !npda : !!npda;
 }
 
 static int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs,
@@ -635,7 +635,7 @@ static struct clk * __init st_clk_register_quadfs_pll(
 
        init.name = name;
        init.ops = quadfs->pll_ops;
-       init.flags = CLK_IS_BASIC;
+       init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE;
        init.parent_names = &parent_name;
        init.num_parents = 1;
 
@@ -774,7 +774,7 @@ static void quadfs_fsynth_disable(struct clk_hw *hw)
        if (fs->lock)
                spin_lock_irqsave(fs->lock, flags);
 
-       CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity);
+       CLKGEN_WRITE(fs, nsb[fs->chan], fs->data->standby_polarity);
 
        if (fs->lock)
                spin_unlock_irqrestore(fs->lock, flags);
@@ -1082,10 +1082,6 @@ static const struct of_device_id quadfs_of_match[] = {
                .compatible = "st,stih407-quadfs660-D",
                .data = &st_fs660c32_D_407
        },
-       {
-               .compatible = "st,stih407-quadfs660-D",
-               .data = (void *)&st_fs660c32_D_407
-       },
        {}
 };
 
index 4fbe6e099587c0541ce9a22783fb2dc4e4becf8c..717c4a91a17b12643146eb028ed02dd0727eac50 100644 (file)
@@ -237,7 +237,7 @@ static struct clk *clk_register_genamux(const char *name,
 
        init.name = name;
        init.ops = &clkgena_divmux_ops;
-       init.flags = CLK_IS_BASIC;
+       init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
 
@@ -513,7 +513,8 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np)
                                          0, &clk_name))
                return;
 
-       clk = clk_register_divider_table(NULL, clk_name, parent_name, 0,
+       clk = clk_register_divider_table(NULL, clk_name, parent_name,
+                                        CLK_GET_RATE_NOCACHE,
                                         reg + data->offset, data->shift, 1,
                                         0, data->table, NULL);
        if (IS_ERR(clk))
@@ -582,7 +583,7 @@ static struct clkgen_mux_data stih416_a9_mux_data = {
 };
 static struct clkgen_mux_data stih407_a9_mux_data = {
        .offset = 0x1a4,
-       .shift = 1,
+       .shift = 0,
        .width = 2,
 };
 
@@ -786,7 +787,8 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np)
                                             &mux->hw, &clk_mux_ops,
                                             &div->hw, &clk_divider_ops,
                                             &gate->hw, &clk_gate_ops,
-                                            data->clk_flags);
+                                            data->clk_flags |
+                                            CLK_GET_RATE_NOCACHE);
                if (IS_ERR(clk)) {
                        kfree(gate);
                        kfree(div);
index 1065322072136bd90c868f9d6a2fd4c56104f303..72d1c27eaffa8247a0e49d029c21d2481caa83a7 100644 (file)
@@ -406,7 +406,7 @@ static struct clk * __init clkgen_pll_register(const char *parent_name,
        init.name = clk_name;
        init.ops = pll_data->ops;
 
-       init.flags = CLK_IS_BASIC;
+       init.flags = CLK_IS_BASIC | CLK_GET_RATE_NOCACHE;
        init.parent_names = &parent_name;
        init.num_parents  = 1;
 
index 9a82f17d2d73daf611ac5e8651e35c2101ea6245..abf7b37faf73f3dd2366024a5bb97affc152cda2 100644 (file)
@@ -1391,6 +1391,7 @@ static void __init sun6i_init_clocks(struct device_node *node)
 CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
 CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
 CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
+CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks);
 
 static void __init sun9i_init_clocks(struct device_node *node)
 {
index b8ff3c64cc452a16fc4108426fb6e5b1c54e91e8..c96de14036a0adebfc7628dc9f9cd5413b5c5495 100644 (file)
@@ -661,6 +661,9 @@ static void sh_cmt_clocksource_suspend(struct clocksource *cs)
 {
        struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
 
+       if (!ch->cs_enabled)
+               return;
+
        sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
        pm_genpd_syscore_poweroff(&ch->cmt->pdev->dev);
 }
@@ -669,6 +672,9 @@ static void sh_cmt_clocksource_resume(struct clocksource *cs)
 {
        struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
 
+       if (!ch->cs_enabled)
+               return;
+
        pm_genpd_syscore_poweron(&ch->cmt->pdev->dev);
        sh_cmt_start(ch, FLAG_CLOCKSOURCE);
 }
index 879c784235469c4cd1a57ecfaa15fdc79ab0d289..86c7eb66bdfb2e18628997319aa047b1aedc1da1 100644 (file)
@@ -462,6 +462,7 @@ void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
        BUG_ON(!imxtm->base);
 
        imxtm->type = type;
+       imxtm->irq = irq;
 
        _mxc_timer_init(imxtm);
 }
@@ -529,6 +530,7 @@ static void __init imx6dl_timer_init_dt(struct device_node *np)
 
 CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
 CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
 CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
 CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
 CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
index b612411655f99309929ae760887c05a8608d01d6..7a3c30c4336f3cb9b7b67d5965b77175b4cad53f 100644 (file)
@@ -169,6 +169,15 @@ struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
 }
 EXPORT_SYMBOL_GPL(get_governor_parent_kobj);
 
+struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+
+       return policy && !policy_is_inactive(policy) ?
+               policy->freq_table : NULL;
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
+
 static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
 {
        u64 idle_time;
@@ -993,7 +1002,7 @@ static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
        int ret = 0;
 
        /* Some related CPUs might not be present (physically hotplugged) */
-       for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) {
+       for_each_cpu(j, policy->real_cpus) {
                if (j == policy->kobj_cpu)
                        continue;
 
@@ -1010,7 +1019,7 @@ static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy)
        unsigned int j;
 
        /* Some related CPUs might not be present (physically hotplugged) */
-       for_each_cpu_and(j, policy->related_cpus, cpu_present_mask) {
+       for_each_cpu(j, policy->real_cpus) {
                if (j == policy->kobj_cpu)
                        continue;
 
@@ -1132,6 +1141,7 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
 
                down_write(&policy->rwsem);
                policy->cpu = cpu;
+               policy->governor = NULL;
                up_write(&policy->rwsem);
        }
 
@@ -1153,11 +1163,14 @@ static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev)
        if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
                goto err_free_cpumask;
 
+       if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
+               goto err_free_rcpumask;
+
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &dev->kobj,
                                   "cpufreq");
        if (ret) {
                pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
-               goto err_free_rcpumask;
+               goto err_free_real_cpus;
        }
 
        INIT_LIST_HEAD(&policy->policy_list);
@@ -1174,6 +1187,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev)
 
        return policy;
 
+err_free_real_cpus:
+       free_cpumask_var(policy->real_cpus);
 err_free_rcpumask:
        free_cpumask_var(policy->related_cpus);
 err_free_cpumask:
@@ -1224,6 +1239,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify)
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        cpufreq_policy_put_kobj(policy, notify);
+       free_cpumask_var(policy->real_cpus);
        free_cpumask_var(policy->related_cpus);
        free_cpumask_var(policy->cpus);
        kfree(policy);
@@ -1248,14 +1264,17 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 
        pr_debug("adding CPU %u\n", cpu);
 
-       /*
-        * Only possible if 'cpu' wasn't physically present earlier and we are
-        * here from subsys_interface add callback. A hotplug notifier will
-        * follow and we will handle it like logical CPU hotplug then. For now,
-        * just create the sysfs link.
-        */
-       if (cpu_is_offline(cpu))
-               return add_cpu_dev_symlink(per_cpu(cpufreq_cpu_data, cpu), cpu);
+       if (cpu_is_offline(cpu)) {
+               /*
+                * Only possible if we are here from the subsys_interface add
+                * callback.  A hotplug notifier will follow and we will handle
+                * it as CPU online then.  For now, just create the sysfs link,
+                * unless there is no policy or the link is already present.
+                */
+               policy = per_cpu(cpufreq_cpu_data, cpu);
+               return policy && !cpumask_test_and_set_cpu(cpu, policy->real_cpus)
+                       ? add_cpu_dev_symlink(policy, cpu) : 0;
+       }
 
        if (!down_read_trylock(&cpufreq_rwsem))
                return 0;
@@ -1297,6 +1316,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
        /* related cpus should atleast have policy->cpus */
        cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
 
+       /* Remember which CPUs have been present at the policy creation time. */
+       if (!recover_policy)
+               cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask);
+
        /*
         * affected cpus must always be the one, which are online. We aren't
         * managing offline cpus here.
@@ -1410,8 +1433,7 @@ nomem_out:
        return ret;
 }
 
-static int __cpufreq_remove_dev_prepare(struct device *dev,
-                                       struct subsys_interface *sif)
+static int __cpufreq_remove_dev_prepare(struct device *dev)
 {
        unsigned int cpu = dev->id;
        int ret = 0;
@@ -1427,10 +1449,8 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
 
        if (has_target()) {
                ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
-               if (ret) {
+               if (ret)
                        pr_err("%s: Failed to stop governor\n", __func__);
-                       return ret;
-               }
        }
 
        down_write(&policy->rwsem);
@@ -1463,8 +1483,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
        return ret;
 }
 
-static int __cpufreq_remove_dev_finish(struct device *dev,
-                                      struct subsys_interface *sif)
+static int __cpufreq_remove_dev_finish(struct device *dev)
 {
        unsigned int cpu = dev->id;
        int ret;
@@ -1482,10 +1501,8 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
        /* If cpu is last user of policy, free policy */
        if (has_target()) {
                ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
-               if (ret) {
+               if (ret)
                        pr_err("%s: Failed to exit governor\n", __func__);
-                       return ret;
-               }
        }
 
        /*
@@ -1496,10 +1513,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
 
-       /* Free the policy only if the driver is getting removed. */
-       if (sif)
-               cpufreq_policy_free(policy, true);
-
        return 0;
 }
 
@@ -1511,42 +1524,41 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
 static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
-       int ret;
-
-       /*
-        * Only possible if 'cpu' is getting physically removed now. A hotplug
-        * notifier should have already been called and we just need to remove
-        * link or free policy here.
-        */
-       if (cpu_is_offline(cpu)) {
-               struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
-               struct cpumask mask;
+       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
 
-               if (!policy)
-                       return 0;
+       if (!policy)
+               return 0;
 
-               cpumask_copy(&mask, policy->related_cpus);
-               cpumask_clear_cpu(cpu, &mask);
+       if (cpu_online(cpu)) {
+               __cpufreq_remove_dev_prepare(dev);
+               __cpufreq_remove_dev_finish(dev);
+       }
 
-               /*
-                * Free policy only if all policy->related_cpus are removed
-                * physically.
-                */
-               if (cpumask_intersects(&mask, cpu_present_mask)) {
-                       remove_cpu_dev_symlink(policy, cpu);
-                       return 0;
-               }
+       cpumask_clear_cpu(cpu, policy->real_cpus);
 
+       if (cpumask_empty(policy->real_cpus)) {
                cpufreq_policy_free(policy, true);
                return 0;
        }
 
-       ret = __cpufreq_remove_dev_prepare(dev, sif);
+       if (cpu != policy->kobj_cpu) {
+               remove_cpu_dev_symlink(policy, cpu);
+       } else {
+               /*
+                * The CPU owning the policy object is going away.  Move it to
+                * another suitable CPU.
+                */
+               unsigned int new_cpu = cpumask_first(policy->real_cpus);
+               struct device *new_dev = get_cpu_device(new_cpu);
 
-       if (!ret)
-               ret = __cpufreq_remove_dev_finish(dev, sif);
+               dev_dbg(dev, "%s: Moving policy object to CPU%u\n", __func__, new_cpu);
 
-       return ret;
+               sysfs_remove_link(&new_dev->kobj, "cpufreq");
+               policy->kobj_cpu = new_cpu;
+               WARN_ON(kobject_move(&policy->kobj, &new_dev->kobj));
+       }
+
+       return 0;
 }
 
 static void handle_update(struct work_struct *work)
@@ -2385,11 +2397,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
                        break;
 
                case CPU_DOWN_PREPARE:
-                       __cpufreq_remove_dev_prepare(dev, NULL);
+                       __cpufreq_remove_dev_prepare(dev);
                        break;
 
                case CPU_POST_DEAD:
-                       __cpufreq_remove_dev_finish(dev, NULL);
+                       __cpufreq_remove_dev_finish(dev);
                        break;
 
                case CPU_DOWN_FAILED:
index ae5b2bd3a9785c63646e3e922fbe17330678b481..fa3dd840a83771735e474a658a5c6516c62f76a0 100644 (file)
@@ -180,7 +180,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
                ret = exynos5250_cpufreq_init(exynos_info);
        } else {
                pr_err("%s: Unknown SoC type\n", __func__);
-               return -ENODEV;
+               ret = -ENODEV;
        }
 
        if (ret)
@@ -188,12 +188,14 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
 
        if (exynos_info->set_freq == NULL) {
                dev_err(&pdev->dev, "No set_freq function (ERR)\n");
+               ret = -EINVAL;
                goto err_vdd_arm;
        }
 
        arm_regulator = regulator_get(NULL, "vdd_arm");
        if (IS_ERR(arm_regulator)) {
                dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
+               ret = -EINVAL;
                goto err_vdd_arm;
        }
 
@@ -225,7 +227,7 @@ err_cpufreq_reg:
        regulator_put(arm_regulator);
 err_vdd_arm:
        kfree(exynos_info);
-       return -EINVAL;
+       return ret;
 }
 
 static struct platform_driver exynos_cpufreq_platdrv = {
index df14766a8e06b7b692807c08d1bf27d683a339eb..dfbbf981ed56fdfd52b147b5c693f764696a56c8 100644 (file)
@@ -297,15 +297,6 @@ int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
 }
 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
 
-struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
-
-struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
-{
-       struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
-       return policy ? policy->freq_table : NULL;
-}
-EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
-
 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
 MODULE_DESCRIPTION("CPUfreq frequency table helpers");
 MODULE_LICENSE("GPL");
index 15ada47bb720b710454795d8d7e83c235c2fccfc..fcb929ec5304a9b233f0d2a55be394e5c1ed25f1 100644 (file)
@@ -681,6 +681,7 @@ static struct cpu_defaults knl_params = {
                .get_max = core_get_max_pstate,
                .get_min = core_get_min_pstate,
                .get_turbo = knl_get_turbo_pstate,
+               .get_scaling = core_get_scaling,
                .set = core_set_pstate,
        },
 };
index fc897babab55c6ec07e0f4c02c7deb856cd34123..cd593c1f66dc8af8a6208933003783e0f37b7392 100644 (file)
@@ -3,7 +3,7 @@
  *
  * The 2E revision of loongson processor not support this feature.
  *
- * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
+ * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology
  * Author: Yanhua, yanh@lemote.com
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -20,7 +20,7 @@
 #include <asm/clock.h>
 #include <asm/idle.h>
 
-#include <asm/mach-loongson/loongson.h>
+#include <asm/mach-loongson64/loongson.h>
 
 static uint nowait;
 
index e8e2775c3821e26dc179ea6e300025d0cf6e75e5..48b7228563ad7b024b17d49dc8ff9b675049f587 100644 (file)
@@ -112,7 +112,12 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
 static void enter_freeze_proper(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev, int index)
 {
-       tick_freeze();
+       /*
+        * trace_suspend_resume() called by tick_freeze() for the last CPU
+        * executing it contains RCU usage regarded as invalid in the idle
+        * context, so tell RCU about that.
+        */
+       RCU_NONIDLE(tick_freeze());
        /*
         * The state used here cannot be a "coupled" one, because the "coupled"
         * cpuidle mechanism enables interrupts and doing that with timekeeping
@@ -122,7 +127,7 @@ static void enter_freeze_proper(struct cpuidle_driver *drv,
        WARN_ON(!irqs_disabled());
        /*
         * timekeeping_resume() that will be called by tick_unfreeze() for the
-        * last CPU executing it calls functions containing RCU read-side
+        * first CPU executing it calls functions containing RCU read-side
         * critical sections, so tell RCU about that.
         */
        RCU_NONIDLE(tick_unfreeze());
index dae1e8099969a192b302703ec291da96ebac3429..f9c78751989ec865491570ed13bf19dbc6b1a799 100644 (file)
@@ -909,13 +909,14 @@ static int ahash_final_ctx(struct ahash_request *req)
                          state->buflen_1;
        u32 *sh_desc = ctx->sh_desc_fin, *desc;
        dma_addr_t ptr = ctx->sh_desc_fin_dma;
-       int sec4_sg_bytes;
+       int sec4_sg_bytes, sec4_sg_src_index;
        int digestsize = crypto_ahash_digestsize(ahash);
        struct ahash_edesc *edesc;
        int ret = 0;
        int sh_len;
 
-       sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry);
+       sec4_sg_src_index = 1 + (buflen ? 1 : 0);
+       sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry);
 
        /* allocate space for base edesc and hw desc commands, link tables */
        edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN +
@@ -942,7 +943,7 @@ static int ahash_final_ctx(struct ahash_request *req)
        state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1,
                                                buf, state->buf_dma, buflen,
                                                last_buflen);
-       (edesc->sec4_sg + sec4_sg_bytes - 1)->len |= SEC4_SG_LEN_FIN;
+       (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN;
 
        edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
                                            sec4_sg_bytes, DMA_TO_DEVICE);
index 7ba495f7537042f898ef1cd7cdba7a6263f2059b..402631a19a112770af83f0f4228176703e1c0b44 100644 (file)
@@ -905,7 +905,6 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt)
                crypt->mode |= NPE_OP_NOT_IN_PLACE;
                /* This was never tested by Intel
                 * for more than one dst buffer, I think. */
-               BUG_ON(req->dst->length < nbytes);
                req_ctx->dst = NULL;
                if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook,
                                        flags, DMA_FROM_DEVICE))
index 67f80813a06f9a780e6573a7dd995f0150c47dcf..e4311ce0cd78cfc93eea1cec30a37a9ec3b54d25 100644 (file)
@@ -494,8 +494,9 @@ out:
 static int ccm4309_aes_nx_encrypt(struct aead_request *req)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
        struct blkcipher_desc desc;
-       u8 *iv = nx_ctx->priv.ccm.iv;
+       u8 *iv = rctx->iv;
 
        iv[0] = 3;
        memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
@@ -525,8 +526,9 @@ static int ccm_aes_nx_encrypt(struct aead_request *req)
 static int ccm4309_aes_nx_decrypt(struct aead_request *req)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
        struct blkcipher_desc desc;
-       u8 *iv = nx_ctx->priv.ccm.iv;
+       u8 *iv = rctx->iv;
 
        iv[0] = 3;
        memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
index 2617cd4d54dd2e458e8a56de967c468a66ef2f09..dd7e9f3f5b6b2edfb0a4e1c1e442523a30d4f74b 100644 (file)
@@ -72,7 +72,7 @@ static int ctr3686_aes_nx_set_key(struct crypto_tfm *tfm,
        if (key_len < CTR_RFC3686_NONCE_SIZE)
                return -EINVAL;
 
-       memcpy(nx_ctx->priv.ctr.iv,
+       memcpy(nx_ctx->priv.ctr.nonce,
               in_key + key_len - CTR_RFC3686_NONCE_SIZE,
               CTR_RFC3686_NONCE_SIZE);
 
@@ -131,14 +131,15 @@ static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc,
                                unsigned int           nbytes)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
-       u8 *iv = nx_ctx->priv.ctr.iv;
+       u8 iv[16];
 
+       memcpy(iv, nx_ctx->priv.ctr.nonce, CTR_RFC3686_IV_SIZE);
        memcpy(iv + CTR_RFC3686_NONCE_SIZE,
               desc->info, CTR_RFC3686_IV_SIZE);
        iv[12] = iv[13] = iv[14] = 0;
        iv[15] = 1;
 
-       desc->info = nx_ctx->priv.ctr.iv;
+       desc->info = iv;
 
        return ctr_aes_nx_crypt(desc, dst, src, nbytes);
 }
index 08ac6d48688c7cf80589965b34724f374ec41b61..92c993f08213fbd767c897eae178a5129c5af899 100644 (file)
@@ -317,6 +317,7 @@ out:
 static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
        struct blkcipher_desc desc;
        unsigned int nbytes = req->cryptlen;
@@ -326,7 +327,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
 
        spin_lock_irqsave(&nx_ctx->lock, irq_flags);
 
-       desc.info = nx_ctx->priv.gcm.iv;
+       desc.info = rctx->iv;
        /* initialize the counter */
        *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1;
 
@@ -424,8 +425,8 @@ out:
 
 static int gcm_aes_nx_encrypt(struct aead_request *req)
 {
-       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
-       char *iv = nx_ctx->priv.gcm.iv;
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
+       char *iv = rctx->iv;
 
        memcpy(iv, req->iv, 12);
 
@@ -434,8 +435,8 @@ static int gcm_aes_nx_encrypt(struct aead_request *req)
 
 static int gcm_aes_nx_decrypt(struct aead_request *req)
 {
-       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
-       char *iv = nx_ctx->priv.gcm.iv;
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
+       char *iv = rctx->iv;
 
        memcpy(iv, req->iv, 12);
 
@@ -445,7 +446,8 @@ static int gcm_aes_nx_decrypt(struct aead_request *req)
 static int gcm4106_aes_nx_encrypt(struct aead_request *req)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
-       char *iv = nx_ctx->priv.gcm.iv;
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
+       char *iv = rctx->iv;
        char *nonce = nx_ctx->priv.gcm.nonce;
 
        memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
@@ -457,7 +459,8 @@ static int gcm4106_aes_nx_encrypt(struct aead_request *req)
 static int gcm4106_aes_nx_decrypt(struct aead_request *req)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
-       char *iv = nx_ctx->priv.gcm.iv;
+       struct nx_gcm_rctx *rctx = aead_request_ctx(req);
+       char *iv = rctx->iv;
        char *nonce = nx_ctx->priv.gcm.nonce;
 
        memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
index 8c2faffab4a35952c7b28bccf04c7ea5f706a471..c2f7d4befb5599fa4e7c947ba25b796c8612d24e 100644 (file)
@@ -42,6 +42,7 @@ static int nx_xcbc_set_key(struct crypto_shash *desc,
                           unsigned int         key_len)
 {
        struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc);
+       struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
 
        switch (key_len) {
        case AES_KEYSIZE_128:
@@ -51,7 +52,7 @@ static int nx_xcbc_set_key(struct crypto_shash *desc,
                return -EINVAL;
        }
 
-       memcpy(nx_ctx->priv.xcbc.key, in_key, key_len);
+       memcpy(csbcpb->cpb.aes_xcbc.key, in_key, key_len);
 
        return 0;
 }
@@ -148,32 +149,29 @@ out:
        return rc;
 }
 
-static int nx_xcbc_init(struct shash_desc *desc)
+static int nx_crypto_ctx_aes_xcbc_init2(struct crypto_tfm *tfm)
 {
-       struct xcbc_state *sctx = shash_desc_ctx(desc);
-       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
-       struct nx_sg *out_sg;
-       int len;
+       int err;
 
-       nx_ctx_init(nx_ctx, HCOP_FC_AES);
+       err = nx_crypto_ctx_aes_xcbc_init(tfm);
+       if (err)
+               return err;
 
-       memset(sctx, 0, sizeof *sctx);
+       nx_ctx_init(nx_ctx, HCOP_FC_AES);
 
        NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
        csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
 
-       memcpy(csbcpb->cpb.aes_xcbc.key, nx_ctx->priv.xcbc.key, AES_BLOCK_SIZE);
-       memset(nx_ctx->priv.xcbc.key, 0, sizeof *nx_ctx->priv.xcbc.key);
-
-       len = AES_BLOCK_SIZE;
-       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
-                                 &len, nx_ctx->ap->sglen);
+       return 0;
+}
 
-       if (len != AES_BLOCK_SIZE)
-               return -EINVAL;
+static int nx_xcbc_init(struct shash_desc *desc)
+{
+       struct xcbc_state *sctx = shash_desc_ctx(desc);
 
-       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+       memset(sctx, 0, sizeof *sctx);
 
        return 0;
 }
@@ -186,6 +184,7 @@ static int nx_xcbc_update(struct shash_desc *desc,
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
        struct nx_sg *in_sg;
+       struct nx_sg *out_sg;
        u32 to_process = 0, leftover, total;
        unsigned int max_sg_len;
        unsigned long irq_flags;
@@ -213,6 +212,17 @@ static int nx_xcbc_update(struct shash_desc *desc,
        max_sg_len = min_t(u64, max_sg_len,
                                nx_ctx->ap->databytelen/NX_PAGE_SIZE);
 
+       data_len = AES_BLOCK_SIZE;
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+                                 &len, nx_ctx->ap->sglen);
+
+       if (data_len != AES_BLOCK_SIZE) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
        do {
                to_process = total - to_process;
                to_process = to_process & ~(AES_BLOCK_SIZE - 1);
@@ -235,8 +245,10 @@ static int nx_xcbc_update(struct shash_desc *desc,
                                                (u8 *) sctx->buffer,
                                                &data_len,
                                                max_sg_len);
-                       if (data_len != sctx->count)
-                               return -EINVAL;
+                       if (data_len != sctx->count) {
+                               rc = -EINVAL;
+                               goto out;
+                       }
                }
 
                data_len = to_process - sctx->count;
@@ -245,8 +257,10 @@ static int nx_xcbc_update(struct shash_desc *desc,
                                        &data_len,
                                        max_sg_len);
 
-               if (data_len != to_process - sctx->count)
-                       return -EINVAL;
+               if (data_len != to_process - sctx->count) {
+                       rc = -EINVAL;
+                       goto out;
+               }
 
                nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
                                        sizeof(struct nx_sg);
@@ -325,15 +339,19 @@ static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
        in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer,
                                 &len, nx_ctx->ap->sglen);
 
-       if (len != sctx->count)
-               return -EINVAL;
+       if (len != sctx->count) {
+               rc = -EINVAL;
+               goto out;
+       }
 
        len = AES_BLOCK_SIZE;
        out_sg = nx_build_sg_list(nx_ctx->out_sg, out, &len,
                                  nx_ctx->ap->sglen);
 
-       if (len != AES_BLOCK_SIZE)
-               return -EINVAL;
+       if (len != AES_BLOCK_SIZE) {
+               rc = -EINVAL;
+               goto out;
+       }
 
        nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
        nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
@@ -372,7 +390,7 @@ struct shash_alg nx_shash_aes_xcbc_alg = {
                .cra_blocksize   = AES_BLOCK_SIZE,
                .cra_module      = THIS_MODULE,
                .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
-               .cra_init        = nx_crypto_ctx_aes_xcbc_init,
+               .cra_init        = nx_crypto_ctx_aes_xcbc_init2,
                .cra_exit        = nx_crypto_ctx_exit,
        }
 };
index 4e91bdb83c594c3491bcb183cddd4021e8d8c596..becb738c897b1b5d93b632e3ab80ed2b146ead5a 100644 (file)
 #include "nx.h"
 
 
-static int nx_sha256_init(struct shash_desc *desc)
+static int nx_crypto_ctx_sha256_init(struct crypto_tfm *tfm)
 {
-       struct sha256_state *sctx = shash_desc_ctx(desc);
-       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
-       struct nx_sg *out_sg;
-       int len;
-       u32 max_sg_len;
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+       int err;
 
-       nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+       err = nx_crypto_ctx_sha_init(tfm);
+       if (err)
+               return err;
 
-       memset(sctx, 0, sizeof *sctx);
+       nx_ctx_init(nx_ctx, HCOP_FC_SHA);
 
        nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA256];
 
        NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256);
 
-       max_sg_len = min_t(u64, nx_ctx->ap->sglen,
-                       nx_driver.of.max_sg_len/sizeof(struct nx_sg));
-       max_sg_len = min_t(u64, max_sg_len,
-                       nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+       return 0;
+}
 
-       len = SHA256_DIGEST_SIZE;
-       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
-                                 &len, max_sg_len);
-       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+static int nx_sha256_init(struct shash_desc *desc) {
+       struct sha256_state *sctx = shash_desc_ctx(desc);
 
-       if (len != SHA256_DIGEST_SIZE)
-               return -EINVAL;
+       memset(sctx, 0, sizeof *sctx);
 
        sctx->state[0] = __cpu_to_be32(SHA256_H0);
        sctx->state[1] = __cpu_to_be32(SHA256_H1);
@@ -77,7 +71,7 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
        struct sha256_state *sctx = shash_desc_ctx(desc);
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
-       struct nx_sg *in_sg;
+       struct nx_sg *out_sg;
        u64 to_process = 0, leftover, total;
        unsigned long irq_flags;
        int rc = 0;
@@ -102,24 +96,28 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
        NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
        NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 
-       in_sg = nx_ctx->in_sg;
        max_sg_len = min_t(u64, nx_ctx->ap->sglen,
                        nx_driver.of.max_sg_len/sizeof(struct nx_sg));
        max_sg_len = min_t(u64, max_sg_len,
                        nx_ctx->ap->databytelen/NX_PAGE_SIZE);
 
+       data_len = SHA256_DIGEST_SIZE;
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+                                 &data_len, max_sg_len);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       if (data_len != SHA256_DIGEST_SIZE) {
+               rc = -EINVAL;
+               goto out;
+       }
+
        do {
-               /*
-                * to_process: the SHA256_BLOCK_SIZE data chunk to process in
-                * this update. This value is also restricted by the sg list
-                * limits.
-                */
-               to_process = total - to_process;
-               to_process = to_process & ~(SHA256_BLOCK_SIZE - 1);
+               int used_sgs = 0;
+               struct nx_sg *in_sg = nx_ctx->in_sg;
 
                if (buf_len) {
                        data_len = buf_len;
-                       in_sg = nx_build_sg_list(nx_ctx->in_sg,
+                       in_sg = nx_build_sg_list(in_sg,
                                                 (u8 *) sctx->buf,
                                                 &data_len,
                                                 max_sg_len);
@@ -128,15 +126,27 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
                                rc = -EINVAL;
                                goto out;
                        }
+                       used_sgs = in_sg - nx_ctx->in_sg;
                }
 
+               /* to_process: SHA256_BLOCK_SIZE aligned chunk to be
+                * processed in this iteration. This value is restricted
+                * by sg list limits and number of sgs we already used
+                * for leftover data. (see above)
+                * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len,
+                * but because data may not be aligned, we need to account
+                * for that too. */
+               to_process = min_t(u64, total,
+                       (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE);
+               to_process = to_process & ~(SHA256_BLOCK_SIZE - 1);
+
                data_len = to_process - buf_len;
                in_sg = nx_build_sg_list(in_sg, (u8 *) data,
                                         &data_len, max_sg_len);
 
                nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
 
-               to_process = (data_len + buf_len);
+               to_process = data_len + buf_len;
                leftover = total - to_process;
 
                /*
@@ -282,7 +292,7 @@ struct shash_alg nx_shash_sha256_alg = {
                .cra_blocksize   = SHA256_BLOCK_SIZE,
                .cra_module      = THIS_MODULE,
                .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
-               .cra_init        = nx_crypto_ctx_sha_init,
+               .cra_init        = nx_crypto_ctx_sha256_init,
                .cra_exit        = nx_crypto_ctx_exit,
        }
 };
index e6a58d2ee62894e369c563f5b826d0342a6a729d..b6e183d58d73d5a4e38fff2925344783e8e581bc 100644 (file)
 #include "nx.h"
 
 
-static int nx_sha512_init(struct shash_desc *desc)
+static int nx_crypto_ctx_sha512_init(struct crypto_tfm *tfm)
 {
-       struct sha512_state *sctx = shash_desc_ctx(desc);
-       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
-       struct nx_sg *out_sg;
-       int len;
-       u32 max_sg_len;
+       struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+       int err;
 
-       nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+       err = nx_crypto_ctx_sha_init(tfm);
+       if (err)
+               return err;
 
-       memset(sctx, 0, sizeof *sctx);
+       nx_ctx_init(nx_ctx, HCOP_FC_SHA);
 
        nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA512];
 
        NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512);
 
-       max_sg_len = min_t(u64, nx_ctx->ap->sglen,
-                       nx_driver.of.max_sg_len/sizeof(struct nx_sg));
-       max_sg_len = min_t(u64, max_sg_len,
-                       nx_ctx->ap->databytelen/NX_PAGE_SIZE);
+       return 0;
+}
 
-       len = SHA512_DIGEST_SIZE;
-       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
-                                 &len, max_sg_len);
-       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+static int nx_sha512_init(struct shash_desc *desc)
+{
+       struct sha512_state *sctx = shash_desc_ctx(desc);
 
-       if (len != SHA512_DIGEST_SIZE)
-               return -EINVAL;
+       memset(sctx, 0, sizeof *sctx);
 
        sctx->state[0] = __cpu_to_be64(SHA512_H0);
        sctx->state[1] = __cpu_to_be64(SHA512_H1);
@@ -76,7 +71,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
        struct sha512_state *sctx = shash_desc_ctx(desc);
        struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
        struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
-       struct nx_sg *in_sg;
+       struct nx_sg *out_sg;
        u64 to_process, leftover = 0, total;
        unsigned long irq_flags;
        int rc = 0;
@@ -101,25 +96,28 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
        NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
        NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
 
-       in_sg = nx_ctx->in_sg;
        max_sg_len = min_t(u64, nx_ctx->ap->sglen,
                        nx_driver.of.max_sg_len/sizeof(struct nx_sg));
        max_sg_len = min_t(u64, max_sg_len,
                        nx_ctx->ap->databytelen/NX_PAGE_SIZE);
 
+       data_len = SHA512_DIGEST_SIZE;
+       out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+                                 &data_len, max_sg_len);
+       nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+       if (data_len != SHA512_DIGEST_SIZE) {
+               rc = -EINVAL;
+               goto out;
+       }
+
        do {
-               /*
-                * to_process: the SHA512_BLOCK_SIZE data chunk to process in
-                * this update. This value is also restricted by the sg list
-                * limits.
-                */
-               to_process = total - leftover;
-               to_process = to_process & ~(SHA512_BLOCK_SIZE - 1);
-               leftover = total - to_process;
+               int used_sgs = 0;
+               struct nx_sg *in_sg = nx_ctx->in_sg;
 
                if (buf_len) {
                        data_len = buf_len;
-                       in_sg = nx_build_sg_list(nx_ctx->in_sg,
+                       in_sg = nx_build_sg_list(in_sg,
                                                 (u8 *) sctx->buf,
                                                 &data_len, max_sg_len);
 
@@ -127,8 +125,20 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
                                rc = -EINVAL;
                                goto out;
                        }
+                       used_sgs = in_sg - nx_ctx->in_sg;
                }
 
+               /* to_process: SHA512_BLOCK_SIZE aligned chunk to be
+                * processed in this iteration. This value is restricted
+                * by sg list limits and number of sgs we already used
+                * for leftover data. (see above)
+                * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len,
+                * but because data may not be aligned, we need to account
+                * for that too. */
+               to_process = min_t(u64, total,
+                       (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE);
+               to_process = to_process & ~(SHA512_BLOCK_SIZE - 1);
+
                data_len = to_process - buf_len;
                in_sg = nx_build_sg_list(in_sg, (u8 *) data,
                                         &data_len, max_sg_len);
@@ -140,7 +150,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
                        goto out;
                }
 
-               to_process = (data_len + buf_len);
+               to_process = data_len + buf_len;
                leftover = total - to_process;
 
                /*
@@ -288,7 +298,7 @@ struct shash_alg nx_shash_sha512_alg = {
                .cra_blocksize   = SHA512_BLOCK_SIZE,
                .cra_module      = THIS_MODULE,
                .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
-               .cra_init        = nx_crypto_ctx_sha_init,
+               .cra_init        = nx_crypto_ctx_sha512_init,
                .cra_exit        = nx_crypto_ctx_exit,
        }
 };
index f6198f29a4a811b0cbcb2fb5062ece5a5d2bb421..436971343ff7732b3be14af822e29fcc922c1e0f 100644 (file)
@@ -713,12 +713,15 @@ static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode)
 /* entry points from the crypto tfm initializers */
 int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm)
 {
+       crypto_aead_set_reqsize(__crypto_aead_cast(tfm),
+                               sizeof(struct nx_ccm_rctx));
        return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
                                  NX_MODE_AES_CCM);
 }
 
 int nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm)
 {
+       crypto_aead_set_reqsize(tfm, sizeof(struct nx_gcm_rctx));
        return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES,
                                  NX_MODE_AES_GCM);
 }
index de3ea8738146ba100faf1ede99f5058d6d6f5824..cdff03a42ae7e883648a981779bed47bb9909c92 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __NX_H__
 #define __NX_H__
 
+#include <crypto/ctr.h>
+
 #define NX_NAME                "nx-crypto"
 #define NX_STRING      "IBM Power7+ Nest Accelerator Crypto Driver"
 #define NX_VERSION     "1.0"
@@ -91,8 +93,11 @@ struct nx_crypto_driver {
 
 #define NX_GCM4106_NONCE_LEN           (4)
 #define NX_GCM_CTR_OFFSET              (12)
-struct nx_gcm_priv {
+struct nx_gcm_rctx {
        u8 iv[16];
+};
+
+struct nx_gcm_priv {
        u8 iauth_tag[16];
        u8 nonce[NX_GCM4106_NONCE_LEN];
 };
@@ -100,8 +105,11 @@ struct nx_gcm_priv {
 #define NX_CCM_AES_KEY_LEN             (16)
 #define NX_CCM4309_AES_KEY_LEN         (19)
 #define NX_CCM4309_NONCE_LEN           (3)
-struct nx_ccm_priv {
+struct nx_ccm_rctx {
        u8 iv[16];
+};
+
+struct nx_ccm_priv {
        u8 b0[16];
        u8 iauth_tag[16];
        u8 oauth_tag[16];
@@ -113,7 +121,7 @@ struct nx_xcbc_priv {
 };
 
 struct nx_ctr_priv {
-       u8 iv[16];
+       u8 nonce[CTR_RFC3686_NONCE_SIZE];
 };
 
 struct nx_crypto_ctx {
index 46307098f8bab497734ca5dbbfb7fe2502ed082f..0a70e46d54165e96ba469088f315386b0947fab0 100644 (file)
@@ -536,9 +536,6 @@ static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
        dmaengine_terminate_all(dd->dma_lch_in);
        dmaengine_terminate_all(dd->dma_lch_out);
 
-       dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
-       dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE);
-
        return err;
 }
 
index 067402c7c2a93fdc02ca3242f918deba460dae91..df427c0e9e7b2c99c8ee6cbe0c91b98c1ff47c43 100644 (file)
@@ -73,7 +73,8 @@
                                       ICP_QAT_HW_CIPHER_KEY_CONVERT, \
                                       ICP_QAT_HW_CIPHER_DECRYPT)
 
-static atomic_t active_dev;
+static DEFINE_MUTEX(algs_lock);
+static unsigned int active_devs;
 
 struct qat_alg_buf {
        uint32_t len;
@@ -1280,7 +1281,10 @@ static struct crypto_alg qat_algs[] = { {
 
 int qat_algs_register(void)
 {
-       if (atomic_add_return(1, &active_dev) == 1) {
+       int ret = 0;
+
+       mutex_lock(&algs_lock);
+       if (++active_devs == 1) {
                int i;
 
                for (i = 0; i < ARRAY_SIZE(qat_algs); i++)
@@ -1289,21 +1293,25 @@ int qat_algs_register(void)
                                CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC :
                                CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
 
-               return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
+               ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
        }
-       return 0;
+       mutex_unlock(&algs_lock);
+       return ret;
 }
 
 int qat_algs_unregister(void)
 {
-       if (atomic_sub_return(1, &active_dev) == 0)
-               return crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
-       return 0;
+       int ret = 0;
+
+       mutex_lock(&algs_lock);
+       if (--active_devs == 0)
+               ret = crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs));
+       mutex_unlock(&algs_lock);
+       return ret;
 }
 
 int qat_algs_init(void)
 {
-       atomic_set(&active_dev, 0);
        crypto_get_default_rng();
        return 0;
 }
index 59892126d1758f9d0e0821fa88ff62094a0c6e74..d3629b7482dda55858a942d084916396f6f473c0 100644 (file)
@@ -48,6 +48,8 @@
        BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
        BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
 
+#define ATC_MAX_DSCR_TRIALS    10
+
 /*
  * Initial number of descriptors to allocate for each channel. This could
  * be increased during dma usage.
@@ -285,28 +287,19 @@ static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
  *
  * @current_len: the number of bytes left before reading CTRLA
  * @ctrla: the value of CTRLA
- * @desc: the descriptor containing the transfer width
  */
-static inline int atc_calc_bytes_left(int current_len, u32 ctrla,
-                                       struct at_desc *desc)
+static inline int atc_calc_bytes_left(int current_len, u32 ctrla)
 {
-       return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width);
-}
+       u32 btsize = (ctrla & ATC_BTSIZE_MAX);
+       u32 src_width = ATC_REG_TO_SRC_WIDTH(ctrla);
 
-/**
- * atc_calc_bytes_left_from_reg - calculates the number of bytes left according
- * to the current value of CTRLA.
- *
- * @current_len: the number of bytes left before reading CTRLA
- * @atchan: the channel to read CTRLA for
- * @desc: the descriptor containing the transfer width
- */
-static inline int atc_calc_bytes_left_from_reg(int current_len,
-                       struct at_dma_chan *atchan, struct at_desc *desc)
-{
-       u32 ctrla = channel_readl(atchan, CTRLA);
-
-       return atc_calc_bytes_left(current_len, ctrla, desc);
+       /*
+        * According to the datasheet, when reading the Control A Register
+        * (ctrla), the Buffer Transfer Size (btsize) bitfield refers to the
+        * number of transfers completed on the Source Interface.
+        * So btsize is always a number of source width transfers.
+        */
+       return current_len - (btsize << src_width);
 }
 
 /**
@@ -320,7 +313,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
        struct at_desc *desc_first = atc_first_active(atchan);
        struct at_desc *desc;
        int ret;
-       u32 ctrla, dscr;
+       u32 ctrla, dscr, trials;
 
        /*
         * If the cookie doesn't match to the currently running transfer then
@@ -346,15 +339,82 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
                 * the channel's DSCR register and compare it against the value
                 * of the hardware linked list structure of each child
                 * descriptor.
+                *
+                * The CTRLA register provides us with the amount of data
+                * already read from the source for the current child
+                * descriptor. So we can compute a more accurate residue by also
+                * removing the number of bytes corresponding to this amount of
+                * data.
+                *
+                * However, the DSCR and CTRLA registers cannot be read both
+                * atomically. Hence a race condition may occur: the first read
+                * register may refer to one child descriptor whereas the second
+                * read may refer to a later child descriptor in the list
+                * because of the DMA transfer progression inbetween the two
+                * reads.
+                *
+                * One solution could have been to pause the DMA transfer, read
+                * the DSCR and CTRLA then resume the DMA transfer. Nonetheless,
+                * this approach presents some drawbacks:
+                * - If the DMA transfer is paused, RX overruns or TX underruns
+                *   are more likey to occur depending on the system latency.
+                *   Taking the USART driver as an example, it uses a cyclic DMA
+                *   transfer to read data from the Receive Holding Register
+                *   (RHR) to avoid RX overruns since the RHR is not protected
+                *   by any FIFO on most Atmel SoCs. So pausing the DMA transfer
+                *   to compute the residue would break the USART driver design.
+                * - The atc_pause() function masks interrupts but we'd rather
+                *   avoid to do so for system latency purpose.
+                *
+                * Then we'd rather use another solution: the DSCR is read a
+                * first time, the CTRLA is read in turn, next the DSCR is read
+                * a second time. If the two consecutive read values of the DSCR
+                * are the same then we assume both refers to the very same
+                * child descriptor as well as the CTRLA value read inbetween
+                * does. For cyclic tranfers, the assumption is that a full loop
+                * is "not so fast".
+                * If the two DSCR values are different, we read again the CTRLA
+                * then the DSCR till two consecutive read values from DSCR are
+                * equal or till the maxium trials is reach.
+                * This algorithm is very unlikely not to find a stable value for
+                * DSCR.
                 */
 
-               ctrla = channel_readl(atchan, CTRLA);
-               rmb(); /* ensure CTRLA is read before DSCR */
                dscr = channel_readl(atchan, DSCR);
+               rmb(); /* ensure DSCR is read before CTRLA */
+               ctrla = channel_readl(atchan, CTRLA);
+               for (trials = 0; trials < ATC_MAX_DSCR_TRIALS; ++trials) {
+                       u32 new_dscr;
+
+                       rmb(); /* ensure DSCR is read after CTRLA */
+                       new_dscr = channel_readl(atchan, DSCR);
+
+                       /*
+                        * If the DSCR register value has not changed inside the
+                        * DMA controller since the previous read, we assume
+                        * that both the dscr and ctrla values refers to the
+                        * very same descriptor.
+                        */
+                       if (likely(new_dscr == dscr))
+                               break;
+
+                       /*
+                        * DSCR has changed inside the DMA controller, so the
+                        * previouly read value of CTRLA may refer to an already
+                        * processed descriptor hence could be outdated.
+                        * We need to update ctrla to match the current
+                        * descriptor.
+                        */
+                       dscr = new_dscr;
+                       rmb(); /* ensure DSCR is read before CTRLA */
+                       ctrla = channel_readl(atchan, CTRLA);
+               }
+               if (unlikely(trials >= ATC_MAX_DSCR_TRIALS))
+                       return -ETIMEDOUT;
 
                /* for the first descriptor we can be more accurate */
                if (desc_first->lli.dscr == dscr)
-                       return atc_calc_bytes_left(ret, ctrla, desc_first);
+                       return atc_calc_bytes_left(ret, ctrla);
 
                ret -= desc_first->len;
                list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
@@ -365,16 +425,14 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
                }
 
                /*
-                * For the last descriptor in the chain we can calculate
+                * For the current descriptor in the chain we can calculate
                 * the remaining bytes using the channel's register.
-                * Note that the transfer width of the first and last
-                * descriptor may differ.
                 */
-               if (!desc->lli.dscr)
-                       ret = atc_calc_bytes_left_from_reg(ret, atchan, desc);
+               ret = atc_calc_bytes_left(ret, ctrla);
        } else {
                /* single transfer */
-               ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first);
+               ctrla = channel_readl(atchan, CTRLA);
+               ret = atc_calc_bytes_left(ret, ctrla);
        }
 
        return ret;
@@ -726,7 +784,6 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
 
        desc->txd.cookie = -EBUSY;
        desc->total_len = desc->len = len;
-       desc->tx_width = dwidth;
 
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
@@ -804,10 +861,6 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        first->txd.cookie = -EBUSY;
        first->total_len = len;
 
-       /* set transfer width for the calculation of the residue */
-       first->tx_width = src_width;
-       prev->tx_width = src_width;
-
        /* set end-of-link to the last link descriptor of list*/
        set_desc_eol(desc);
 
@@ -956,10 +1009,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        first->txd.cookie = -EBUSY;
        first->total_len = total_len;
 
-       /* set transfer width for the calculation of the residue */
-       first->tx_width = reg_width;
-       prev->tx_width = reg_width;
-
        /* first link descriptor of list is responsible of flags */
        first->txd.flags = flags; /* client is in control of this ack */
 
@@ -1077,12 +1126,6 @@ atc_prep_dma_sg(struct dma_chan *chan,
                desc->txd.cookie = 0;
                desc->len = len;
 
-               /*
-                * Although we only need the transfer width for the first and
-                * the last descriptor, its easier to set it to all descriptors.
-                */
-               desc->tx_width = src_width;
-
                atc_desc_chain(&first, &prev, desc);
 
                /* update the lengths and addresses for the next loop cycle */
@@ -1256,7 +1299,6 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
        /* First descriptor of the chain embedds additional information */
        first->txd.cookie = -EBUSY;
        first->total_len = buf_len;
-       first->tx_width = reg_width;
 
        return &first->txd;
 
index bc8d5ebedd192f12f9ed32f220c45892c064a8d0..7f5a08230f76de64e044964f8ff49b5051a9bbb2 100644 (file)
 #define                ATC_SRC_WIDTH_BYTE      (0x0 << 24)
 #define                ATC_SRC_WIDTH_HALFWORD  (0x1 << 24)
 #define                ATC_SRC_WIDTH_WORD      (0x2 << 24)
+#define                ATC_REG_TO_SRC_WIDTH(r) (((r) >> 24) & 0x3)
 #define        ATC_DST_WIDTH_MASK      (0x3 << 28)     /* Destination Single Transfer Size */
 #define                ATC_DST_WIDTH(x)        ((x) << 28)
 #define                ATC_DST_WIDTH_BYTE      (0x0 << 28)
@@ -182,7 +183,6 @@ struct at_lli {
  * @txd: support for the async_tx api
  * @desc_node: node on the channed descriptors list
  * @len: descriptor byte count
- * @tx_width: transfer width
  * @total_len: total transaction byte count
  */
 struct at_desc {
@@ -194,7 +194,6 @@ struct at_desc {
        struct dma_async_tx_descriptor  txd;
        struct list_head                desc_node;
        size_t                          len;
-       u32                             tx_width;
        size_t                          total_len;
 
        /* Interleaved data */
index cf1213de7865ecb95e20c9d273a57ec1981203a7..40afa2a16cfc00f17d696833e75d250dabda0e6c 100644 (file)
@@ -359,18 +359,19 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
         * descriptor view 2 since some fields of the configuration register
         * depend on transfer size and src/dest addresses.
         */
-       if (at_xdmac_chan_is_cyclic(atchan)) {
+       if (at_xdmac_chan_is_cyclic(atchan))
                reg = AT_XDMAC_CNDC_NDVIEW_NDV1;
-               at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg);
-       } else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3) {
+       else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3)
                reg = AT_XDMAC_CNDC_NDVIEW_NDV3;
-       } else {
-               /*
-                * No need to write AT_XDMAC_CC reg, it will be done when the
-                * descriptor is fecthed.
-                */
+       else
                reg = AT_XDMAC_CNDC_NDVIEW_NDV2;
-       }
+       /*
+        * Even if the register will be updated from the configuration in the
+        * descriptor when using view 2 or higher, the PROT bit won't be set
+        * properly. This bit can be modified only by using the channel
+        * configuration register.
+        */
+       at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg);
 
        reg |= AT_XDMAC_CNDC_NDDUP
               | AT_XDMAC_CNDC_NDSUP
@@ -681,15 +682,16 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        desc->lld.mbr_sa = mem;
                        desc->lld.mbr_da = atchan->sconfig.dst_addr;
                }
-               desc->lld.mbr_cfg = atchan->cfg;
-               dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
+               dwidth = at_xdmac_get_dwidth(atchan->cfg);
                fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
-                              ? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
+                              ? dwidth
                               : AT_XDMAC_CC_DWIDTH_BYTE;
                desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2                       /* next descriptor view */
                        | AT_XDMAC_MBR_UBC_NDEN                                 /* next descriptor dst parameter update */
                        | AT_XDMAC_MBR_UBC_NSEN                                 /* next descriptor src parameter update */
                        | (len >> fixed_dwidth);                                /* microblock length */
+               desc->lld.mbr_cfg = (atchan->cfg & ~AT_XDMAC_CC_DWIDTH_MASK) |
+                                   AT_XDMAC_CC_DWIDTH(fixed_dwidth);
                dev_dbg(chan2dev(chan),
                         "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
                         __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc);
index 4a4cce15f25dd65c6a720d949ed0d9c922ff1cba..3ff284c8e3d5aef72f229017c883c73cbe13403f 100644 (file)
@@ -689,6 +689,10 @@ struct dma_chan *dma_request_slave_channel(struct device *dev,
        struct dma_chan *ch = dma_request_slave_channel_reason(dev, name);
        if (IS_ERR(ch))
                return NULL;
+
+       dma_cap_set(DMA_PRIVATE, ch->device->cap_mask);
+       ch->device->privatecnt++;
+
        return ch;
 }
 EXPORT_SYMBOL_GPL(dma_request_slave_channel);
index 1022c2e1a2b0adeac7e5954cd55363e2df7f7dab..cf1c87fa1edd557eb57f53dd41c11c02a440ea82 100644 (file)
@@ -1746,4 +1746,4 @@ EXPORT_SYMBOL_GPL(dw_dma_enable);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
 MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
index fbaf1ead25971542ca81acd9f7ddc14161acf340..f1325f62563e2cdf957f33706d620570202d7faf 100644 (file)
@@ -162,10 +162,11 @@ static void mv_chan_set_mode(struct mv_xor_chan *chan,
        config &= ~0x7;
        config |= op_mode;
 
-       if (IS_ENABLED(__BIG_ENDIAN))
-               config |= XOR_DESCRIPTOR_SWAP;
-       else
-               config &= ~XOR_DESCRIPTOR_SWAP;
+#if defined(__BIG_ENDIAN)
+       config |= XOR_DESCRIPTOR_SWAP;
+#else
+       config &= ~XOR_DESCRIPTOR_SWAP;
+#endif
 
        writel_relaxed(config, XOR_CONFIG(chan));
        chan->current_type = type;
index f513f77b1d85471ff0997f8d9f4755deca293621..ecab4ea059b4d5eec80a3f3354b5c1c2c36343c0 100644 (file)
@@ -2328,7 +2328,7 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
                        desc->txd.callback = last->txd.callback;
                        desc->txd.callback_param = last->txd.callback_param;
                }
-               last->last = false;
+               desc->last = false;
 
                dma_cookie_assign(&desc->txd);
 
@@ -2623,6 +2623,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
                desc->rqcfg.brst_len = 1;
 
        desc->rqcfg.brst_len = get_burst_len(desc, len);
+       desc->bytes_requested = len;
 
        desc->txd.flags = flags;
 
index 7d2c17d8d30fc1a4f1efd9c7471bc1e5cbdc794c..6f80432a3f0a3d74bf9a4612712ad6edf4875edc 100644 (file)
@@ -29,7 +29,7 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
        spin_lock_irqsave(&vc->lock, flags);
        cookie = dma_cookie_assign(tx);
 
-       list_move_tail(&vd->node, &vc->desc_submitted);
+       list_add_tail(&vd->node, &vc->desc_submitted);
        spin_unlock_irqrestore(&vc->lock, flags);
 
        dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
@@ -83,10 +83,8 @@ static void vchan_complete(unsigned long arg)
                cb_data = vd->tx.callback_param;
 
                list_del(&vd->node);
-               if (async_tx_test_ack(&vd->tx))
-                       list_add(&vd->node, &vc->desc_allocated);
-               else
-                       vc->desc_free(vd);
+
+               vc->desc_free(vd);
 
                if (cb)
                        cb(cb_data);
@@ -98,13 +96,9 @@ void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
        while (!list_empty(head)) {
                struct virt_dma_desc *vd = list_first_entry(head,
                        struct virt_dma_desc, node);
-               if (async_tx_test_ack(&vd->tx)) {
-                       list_move_tail(&vd->node, &vc->desc_allocated);
-               } else {
-                       dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
-                       list_del(&vd->node);
-                       vc->desc_free(vd);
-               }
+               list_del(&vd->node);
+               dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
+               vc->desc_free(vd);
        }
 }
 EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
@@ -114,7 +108,6 @@ void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
        dma_cookie_init(&vc->chan);
 
        spin_lock_init(&vc->lock);
-       INIT_LIST_HEAD(&vc->desc_allocated);
        INIT_LIST_HEAD(&vc->desc_submitted);
        INIT_LIST_HEAD(&vc->desc_issued);
        INIT_LIST_HEAD(&vc->desc_completed);
index 189e75dbcb15f95876a81848ecde8196a4c82905..181b95267866b605f521860f973aa3860d694fa0 100644 (file)
@@ -29,7 +29,6 @@ struct virt_dma_chan {
        spinlock_t lock;
 
        /* protected by vc.lock */
-       struct list_head desc_allocated;
        struct list_head desc_submitted;
        struct list_head desc_issued;
        struct list_head desc_completed;
@@ -56,16 +55,11 @@ static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan
        struct virt_dma_desc *vd, unsigned long tx_flags)
 {
        extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
-       unsigned long flags;
 
        dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
        vd->tx.flags = tx_flags;
        vd->tx.tx_submit = vchan_tx_submit;
 
-       spin_lock_irqsave(&vc->lock, flags);
-       list_add_tail(&vd->node, &vc->desc_allocated);
-       spin_unlock_irqrestore(&vc->lock, flags);
-
        return &vd->tx;
 }
 
@@ -128,8 +122,7 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
 }
 
 /**
- * vchan_get_all_descriptors - obtain all allocated, submitted and issued
- *                             descriptors
+ * vchan_get_all_descriptors - obtain all submitted and issued descriptors
  * vc: virtual channel to get descriptors from
  * head: list of descriptors found
  *
@@ -141,7 +134,6 @@ static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
 static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
        struct list_head *head)
 {
-       list_splice_tail_init(&vc->desc_allocated, head);
        list_splice_tail_init(&vc->desc_submitted, head);
        list_splice_tail_init(&vc->desc_issued, head);
        list_splice_tail_init(&vc->desc_completed, head);
@@ -149,14 +141,11 @@ static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
 
 static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
 {
-       struct virt_dma_desc *vd;
        unsigned long flags;
        LIST_HEAD(head);
 
        spin_lock_irqsave(&vc->lock, flags);
        vchan_get_all_descriptors(vc, &head);
-       list_for_each_entry(vd, &head, node)
-               async_tx_clear_ack(&vd->tx);
        spin_unlock_irqrestore(&vc->lock, flags);
 
        vchan_dma_desc_free_list(vc, &head);
index 620fd55ec7660b053a511b8237e54fc46118f407..dff22ab01851aadb37fd434a334cf6cc681cf29c 100644 (file)
 #define XGENE_DMA_MEM_RAM_SHUTDOWN             0xD070
 #define XGENE_DMA_BLK_MEM_RDY                  0xD074
 #define XGENE_DMA_BLK_MEM_RDY_VAL              0xFFFFFFFF
+#define XGENE_DMA_RING_CMD_SM_OFFSET           0x8000
 
 /* X-Gene SoC EFUSE csr register and bit defination */
 #define XGENE_SOC_JTAG1_SHADOW                 0x18
@@ -1887,6 +1888,8 @@ static int xgene_dma_get_resources(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       pdma->csr_ring_cmd += XGENE_DMA_RING_CMD_SM_OFFSET;
+
        /* Get efuse csr region */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
        if (!res) {
index 3515b381c1312612f56953bc267ee7d5d23b0f84..711d8ad74f116ebdcc7fd3833fbc0672c7a6359b 100644 (file)
@@ -920,7 +920,7 @@ static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
         */
 
        for (row = 0; row < mci->nr_csrows; row++) {
-               struct csrow_info *csi = &mci->csrows[row];
+               struct csrow_info *csi = mci->csrows[row];
 
                /*
                 * Get the configuration settings for this
index 080d5cc2705529962d2a62b17fe3f597b5bc41e3..eebdf2a33bfe4b84e1fc1886e7222641f4a56122 100644 (file)
@@ -200,7 +200,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
        status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
        if (status) {
                dev_err(&pdev->dev, "failed to register extcon device\n");
-               kfree(palmas_usb->edev->name);
                return status;
        }
 
@@ -214,7 +213,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                if (status < 0) {
                        dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
                                        palmas_usb->id_irq, status);
-                       kfree(palmas_usb->edev->name);
                        return status;
                }
        }
@@ -229,7 +227,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
                if (status < 0) {
                        dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
                                        palmas_usb->vbus_irq, status);
-                       kfree(palmas_usb->edev->name);
                        return status;
                }
        }
@@ -239,15 +236,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int palmas_usb_remove(struct platform_device *pdev)
-{
-       struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
-
-       kfree(palmas_usb->edev->name);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int palmas_usb_suspend(struct device *dev)
 {
@@ -288,7 +276,6 @@ static const struct of_device_id of_palmas_match_tbl[] = {
 
 static struct platform_driver palmas_usb_driver = {
        .probe = palmas_usb_probe,
-       .remove = palmas_usb_remove,
        .driver = {
                .name = "palmas-usb",
                .of_match_table = of_palmas_match_tbl,
index 76157ab9faf3ad84a16e738a4e338ad1bded8e3c..43b57b02d050d197fe7994ea744231b7a580eb23 100644 (file)
@@ -124,25 +124,35 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id
        return -EINVAL;
 }
 
-static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+static int find_cable_id_by_name(struct extcon_dev *edev, const char *name)
 {
-       unsigned int id = EXTCON_NONE;
+       unsigned int id = -EINVAL;
        int i = 0;
 
-       if (edev->max_supported == 0)
-               return -EINVAL;
-
-       /* Find the the number of extcon cable */
+       /* Find the id of extcon cable */
        while (extcon_name[i]) {
                if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
                        id = i;
                        break;
                }
+               i++;
        }
 
-       if (id == EXTCON_NONE)
+       return id;
+}
+
+static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
+{
+       unsigned int id;
+
+       if (edev->max_supported == 0)
                return -EINVAL;
 
+       /* Find the the number of extcon cable */
+       id = find_cable_id_by_name(edev, name);
+       if (id < 0)
+               return id;
+
        return find_cable_index_by_id(edev, id);
 }
 
@@ -228,9 +238,11 @@ static ssize_t cable_state_show(struct device *dev,
        struct extcon_cable *cable = container_of(attr, struct extcon_cable,
                                                  attr_state);
 
+       int i = cable->cable_index;
+
        return sprintf(buf, "%d\n",
                       extcon_get_cable_state_(cable->edev,
-                                              cable->cable_index));
+                                              cable->edev->supported_cable[i]));
 }
 
 /**
@@ -263,20 +275,25 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
        spin_lock_irqsave(&edev->lock, flags);
 
        if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+               u32 old_state;
+
                if (check_mutually_exclusive(edev, (edev->state & ~mask) |
                                                   (state & mask))) {
                        spin_unlock_irqrestore(&edev->lock, flags);
                        return -EPERM;
                }
 
-               for (index = 0; index < edev->max_supported; index++) {
-                       if (is_extcon_changed(edev->state, state, index, &attached))
-                               raw_notifier_call_chain(&edev->nh[index], attached, edev);
-               }
-
+               old_state = edev->state;
                edev->state &= ~mask;
                edev->state |= state & mask;
 
+               for (index = 0; index < edev->max_supported; index++) {
+                       if (is_extcon_changed(old_state, edev->state, index,
+                                             &attached))
+                               raw_notifier_call_chain(&edev->nh[index],
+                                                       attached, edev);
+               }
+
                /* This could be in interrupt handler */
                prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
                if (prop_buf) {
@@ -361,8 +378,13 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
  */
 int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
 {
-       return extcon_get_cable_state_(edev, find_cable_index_by_name
-                                               (edev, cable_name));
+       unsigned int id;
+
+       id = find_cable_id_by_name(edev, cable_name);
+       if (id < 0)
+               return id;
+
+       return extcon_get_cable_state_(edev, id);
 }
 EXPORT_SYMBOL_GPL(extcon_get_cable_state);
 
@@ -404,8 +426,13 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
 int extcon_set_cable_state(struct extcon_dev *edev,
                        const char *cable_name, bool cable_state)
 {
-       return extcon_set_cable_state_(edev, find_cable_index_by_name
-                                       (edev, cable_name), cable_state);
+       unsigned int id;
+
+       id = find_cable_id_by_name(edev, cable_name);
+       if (id < 0)
+               return id;
+
+       return extcon_set_cable_state_(edev, id, cable_state);
 }
 EXPORT_SYMBOL_GPL(extcon_set_cable_state);
 
index 87add3fdce529b1ad6890cb24adb345275e4655c..e41594510b978291de179182c46b0196b3a377e3 100644 (file)
@@ -245,4 +245,4 @@ char *bcm47xx_nvram_get_contents(size_t *nvram_size)
 }
 EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
 
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
index 4fd9961d552e8a0c12604f1cfef83f2e15bea66d..d4253742543841d6d261dfea22156259b0a13183 100644 (file)
@@ -305,10 +305,17 @@ const char *cper_mem_err_unpack(struct trace_seq *p,
        return ret;
 }
 
-static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
+static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
+       int len)
 {
        struct cper_mem_err_compact cmem;
 
+       /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
+       if (len == sizeof(struct cper_sec_mem_err_old) &&
+           (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
+               pr_err(FW_WARN "valid bits set for fields beyond structure\n");
+               return;
+       }
        if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
                printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
        if (mem->validation_bits & CPER_MEM_VALID_PA)
@@ -405,8 +412,10 @@ static void cper_estatus_print_section(
        } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
                struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
                printk("%s""section_type: memory error\n", newpfx);
-               if (gdata->error_data_length >= sizeof(*mem_err))
-                       cper_print_mem(newpfx, mem_err);
+               if (gdata->error_data_length >=
+                   sizeof(struct cper_sec_mem_err_old))
+                       cper_print_mem(newpfx, mem_err,
+                                      gdata->error_data_length);
                else
                        goto err_section_too_small;
        } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
index 9fa8084a7c8d7d9e5aff23bdd372af512e39047a..d6144e3b97c54235ca45a0ad71872957a36ffe48 100644 (file)
@@ -58,6 +58,11 @@ bool efi_runtime_disabled(void)
 
 static int __init parse_efi_cmdline(char *str)
 {
+       if (!str) {
+               pr_warn("need at least one option\n");
+               return -EINVAL;
+       }
+
        if (parse_option_str(str, "noruntime"))
                disable_runtime = true;
 
index 7a3cb1fa0a766a55996f1ae13853905a95e20570..4630a8133ea6b94726a84c48486ff75eb4075bb2 100644 (file)
@@ -87,6 +87,15 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
        struct brcmstb_gpio_bank *bank;
        int ret = 0;
 
+       if (!priv) {
+               dev_err(&pdev->dev, "called %s without drvdata!\n", __func__);
+               return -EFAULT;
+       }
+
+       /*
+        * You can lose return values below, but we report all errors, and it's
+        * more important to actually perform all of the steps.
+        */
        list_for_each(pos, &priv->bank_list) {
                bank = list_entry(pos, struct brcmstb_gpio_bank, node);
                ret = bgpio_remove(&bank->bgc);
@@ -143,6 +152,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
+       platform_set_drvdata(pdev, priv);
+       INIT_LIST_HEAD(&priv->bank_list);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        reg_base = devm_ioremap_resource(dev, res);
@@ -153,7 +164,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
        priv->reg_base = reg_base;
        priv->pdev = pdev;
 
-       INIT_LIST_HEAD(&priv->bank_list);
        if (brcmstb_gpio_sanity_check_banks(dev, np, res))
                return -EINVAL;
 
@@ -221,8 +231,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
        dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
                        priv->num_banks, priv->gpio_base, gpio_base - 1);
 
-       platform_set_drvdata(pdev, priv);
-
        return 0;
 
 fail:
index c5e05c82d67c6c2cd8fdeac5996413e99455a3d1..c246ac3dda7ca2ba0cfa443b8e0175dc176d8da9 100644 (file)
@@ -578,15 +578,13 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
                writel_relaxed(~0, &g->clr_falling);
                writel_relaxed(~0, &g->clr_rising);
 
-               /* set up all irqs in this bank */
-               irq_set_chained_handler(bank_irq, gpio_irq_handler);
-
                /*
                 * Each chip handles 32 gpios, and each irq bank consists of 16
                 * gpio irqs. Pass the irq bank's corresponding controller to
                 * the chained irq handler.
                 */
-               irq_set_handler_data(bank_irq, &chips[gpio / 32]);
+               irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler,
+                                                &chips[gpio / 32]);
 
                binten |= BIT(bank);
        }
index aed4ca9338bca1e15d8a3052438d68635661e01e..7d3c90e9da71a313fcbac511097f159c80b15132 100644 (file)
@@ -603,6 +603,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip,
        gc->base = gpio_start;
        gc->ngpio = port;
        gc->label = chip->client->name;
+       gc->dev = &chip->client->dev;
        gc->owner = THIS_MODULE;
 
        return port;
index b0c57d505be75ac133455a287dc092ff83f3283c..61a731ff9a076fccd0c9b2bdc15d3ca10ce5e21c 100644 (file)
@@ -500,8 +500,10 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
 
        spin_lock_irqsave(&bank->lock, flags);
        retval = omap_set_gpio_triggering(bank, offset, type);
-       if (retval)
+       if (retval) {
+               spin_unlock_irqrestore(&bank->lock, flags);
                goto error;
+       }
        omap_gpio_init_irq(bank, offset);
        if (!omap_gpio_is_input(bank, offset)) {
                spin_unlock_irqrestore(&bank->lock, flags);
@@ -1185,6 +1187,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
        bank->irq = res->start;
        bank->dev = dev;
        bank->chip.dev = dev;
+       bank->chip.owner = THIS_MODULE;
        bank->dbck_flag = pdata->dbck_flag;
        bank->stride = pdata->bank_stride;
        bank->width = pdata->bank_width;
index d233eb3b81323342bb5a22122c1b1f570678c8b1..50caeb1ee3509da04b57d38dd332396e76ea25de 100644 (file)
@@ -570,6 +570,10 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                                "could not connect irqchip to gpiochip\n");
                        return ret;
                }
+
+               gpiochip_set_chained_irqchip(&chip->gpio_chip,
+                                            &pca953x_irq_chip,
+                                            client->irq, NULL);
        }
 
        return 0;
index 77fe5d3cb105b97057aab4b900ba595a837f4e50..d5284dfe01fe167e9da6c6c4f8342d67d8380b20 100644 (file)
@@ -220,9 +220,9 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
        if (!chip->gpio_width[1])
                return;
 
-       xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_TRI_OFFSET,
+       xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
                       chip->gpio_state[1]);
-       xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_TRI_OFFSET,
+       xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
                       chip->gpio_dir[1]);
 }
 
index 2e87c4b8da26d5336164359a6a6e27f0a32de68c..a78882389836071510bbcd5548ce426e894868ab 100644 (file)
@@ -757,6 +757,7 @@ static int zynq_gpio_remove(struct platform_device *pdev)
        gpiochip_remove(&gpio->chip);
        clk_disable_unprepare(gpio->clk);
        device_set_wakeup_capable(&pdev->dev, 0);
+       pm_runtime_disable(&pdev->dev);
        return 0;
 }
 
index 01657830b470a49e8209fd39fa829d4a1fbb3610..f7b49d5ce4b81d471fa3c84280560b9d0e774c78 100644 (file)
@@ -1130,6 +1130,9 @@ struct amdgpu_gfx {
        uint32_t                        me_feature_version;
        uint32_t                        ce_feature_version;
        uint32_t                        pfp_feature_version;
+       uint32_t                        rlc_feature_version;
+       uint32_t                        mec_feature_version;
+       uint32_t                        mec2_feature_version;
        struct amdgpu_ring              gfx_ring[AMDGPU_MAX_GFX_RINGS];
        unsigned                        num_gfx_rings;
        struct amdgpu_ring              compute_ring[AMDGPU_MAX_COMPUTE_RINGS];
@@ -1614,6 +1617,9 @@ struct amdgpu_uvd {
 #define AMDGPU_MAX_VCE_HANDLES 16
 #define AMDGPU_VCE_FIRMWARE_OFFSET 256
 
+#define AMDGPU_VCE_HARVEST_VCE0 (1 << 0)
+#define AMDGPU_VCE_HARVEST_VCE1 (1 << 1)
+
 struct amdgpu_vce {
        struct amdgpu_bo        *vcpu_bo;
        uint64_t                gpu_addr;
@@ -1626,6 +1632,7 @@ struct amdgpu_vce {
        const struct firmware   *fw;    /* VCE firmware */
        struct amdgpu_ring      ring[AMDGPU_MAX_VCE_RINGS];
        struct amdgpu_irq_src   irq;
+       unsigned                harvest_config;
 };
 
 /*
@@ -1635,6 +1642,7 @@ struct amdgpu_sdma {
        /* SDMA firmware */
        const struct firmware   *fw;
        uint32_t                fw_version;
+       uint32_t                feature_version;
 
        struct amdgpu_ring      ring;
 };
@@ -1862,6 +1870,12 @@ typedef void (*amdgpu_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
 typedef uint32_t (*amdgpu_block_rreg_t)(struct amdgpu_device*, uint32_t, uint32_t);
 typedef void (*amdgpu_block_wreg_t)(struct amdgpu_device*, uint32_t, uint32_t, uint32_t);
 
+struct amdgpu_ip_block_status {
+       bool valid;
+       bool sw;
+       bool hw;
+};
+
 struct amdgpu_device {
        struct device                   *dev;
        struct drm_device               *ddev;
@@ -2004,7 +2018,7 @@ struct amdgpu_device {
 
        const struct amdgpu_ip_block_version *ip_blocks;
        int                             num_ip_blocks;
-       bool                            *ip_block_enabled;
+       struct amdgpu_ip_block_status   *ip_block_status;
        struct mutex    mn_lock;
        DECLARE_HASHTABLE(mn_hash, 7);
 
index d63135bf29c0c258f72025fa6f41f34677576ec4..1f040d85ac47fe336f609a0cf9d39ac59b94f665 100644 (file)
@@ -669,6 +669,7 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
 static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
                                  struct amdgpu_cs_parser *p)
 {
+       struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
        struct amdgpu_ib *ib;
        int i, j, r;
 
@@ -694,6 +695,7 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
                for (j = 0; j < num_deps; ++j) {
                        struct amdgpu_fence *fence;
                        struct amdgpu_ring *ring;
+                       struct amdgpu_ctx *ctx;
 
                        r = amdgpu_cs_get_ring(adev, deps[j].ip_type,
                                               deps[j].ip_instance,
@@ -701,14 +703,21 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev,
                        if (r)
                                return r;
 
+                       ctx = amdgpu_ctx_get(fpriv, deps[j].ctx_id);
+                       if (ctx == NULL)
+                               return -EINVAL;
+
                        r = amdgpu_fence_recreate(ring, p->filp,
                                                  deps[j].handle,
                                                  &fence);
-                       if (r)
+                       if (r) {
+                               amdgpu_ctx_put(ctx);
                                return r;
+                       }
 
                        amdgpu_sync_fence(&ib->sync, fence);
                        amdgpu_fence_unref(&fence);
+                       amdgpu_ctx_put(ctx);
                }
        }
 
@@ -808,12 +817,16 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data,
 
        r = amdgpu_cs_get_ring(adev, wait->in.ip_type, wait->in.ip_instance,
                               wait->in.ring, &ring);
-       if (r)
+       if (r) {
+               amdgpu_ctx_put(ctx);
                return r;
+       }
 
        r = amdgpu_fence_recreate(ring, filp, wait->in.handle, &fence);
-       if (r)
+       if (r) {
+               amdgpu_ctx_put(ctx);
                return r;
+       }
 
        r = fence_wait_timeout(&fence->base, true, timeout);
        amdgpu_fence_unref(&fence);
index ba46be361c9b2c9f40bf0acb751e65b156d4b171..99f158e1baffa711073d1251d6d05c72cb68976e 100644 (file)
@@ -1191,8 +1191,9 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
                return -EINVAL;
        }
 
-       adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL);
-       if (adev->ip_block_enabled == NULL)
+       adev->ip_block_status = kcalloc(adev->num_ip_blocks,
+                                       sizeof(struct amdgpu_ip_block_status), GFP_KERNEL);
+       if (adev->ip_block_status == NULL)
                return -ENOMEM;
 
        if (adev->ip_blocks == NULL) {
@@ -1203,14 +1204,19 @@ static int amdgpu_early_init(struct amdgpu_device *adev)
        for (i = 0; i < adev->num_ip_blocks; i++) {
                if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
                        DRM_ERROR("disabled ip block: %d\n", i);
-                       adev->ip_block_enabled[i] = false;
+                       adev->ip_block_status[i].valid = false;
                } else {
                        if (adev->ip_blocks[i].funcs->early_init) {
                                r = adev->ip_blocks[i].funcs->early_init((void *)adev);
-                               if (r)
+                               if (r == -ENOENT)
+                                       adev->ip_block_status[i].valid = false;
+                               else if (r)
                                        return r;
+                               else
+                                       adev->ip_block_status[i].valid = true;
+                       } else {
+                               adev->ip_block_status[i].valid = true;
                        }
-                       adev->ip_block_enabled[i] = true;
                }
        }
 
@@ -1222,11 +1228,12 @@ static int amdgpu_init(struct amdgpu_device *adev)
        int i, r;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                r = adev->ip_blocks[i].funcs->sw_init((void *)adev);
                if (r)
                        return r;
+               adev->ip_block_status[i].sw = true;
                /* need to do gmc hw init early so we can allocate gpu mem */
                if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
                        r = amdgpu_vram_scratch_init(adev);
@@ -1238,11 +1245,12 @@ static int amdgpu_init(struct amdgpu_device *adev)
                        r = amdgpu_wb_init(adev);
                        if (r)
                                return r;
+                       adev->ip_block_status[i].hw = true;
                }
        }
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].sw)
                        continue;
                /* gmc hw init is done early */
                if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC)
@@ -1250,6 +1258,7 @@ static int amdgpu_init(struct amdgpu_device *adev)
                r = adev->ip_blocks[i].funcs->hw_init((void *)adev);
                if (r)
                        return r;
+               adev->ip_block_status[i].hw = true;
        }
 
        return 0;
@@ -1260,7 +1269,7 @@ static int amdgpu_late_init(struct amdgpu_device *adev)
        int i = 0, r;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                /* enable clockgating to save power */
                r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
@@ -1282,7 +1291,7 @@ static int amdgpu_fini(struct amdgpu_device *adev)
        int i, r;
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].hw)
                        continue;
                if (adev->ip_blocks[i].type == AMD_IP_BLOCK_TYPE_GMC) {
                        amdgpu_wb_fini(adev);
@@ -1295,14 +1304,16 @@ static int amdgpu_fini(struct amdgpu_device *adev)
                        return r;
                r = adev->ip_blocks[i].funcs->hw_fini((void *)adev);
                /* XXX handle errors */
+               adev->ip_block_status[i].hw = false;
        }
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].sw)
                        continue;
                r = adev->ip_blocks[i].funcs->sw_fini((void *)adev);
                /* XXX handle errors */
-               adev->ip_block_enabled[i] = false;
+               adev->ip_block_status[i].sw = false;
+               adev->ip_block_status[i].valid = false;
        }
 
        return 0;
@@ -1313,7 +1324,7 @@ static int amdgpu_suspend(struct amdgpu_device *adev)
        int i, r;
 
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                /* ungate blocks so that suspend can properly shut them down */
                r = adev->ip_blocks[i].funcs->set_clockgating_state((void *)adev,
@@ -1331,7 +1342,7 @@ static int amdgpu_resume(struct amdgpu_device *adev)
        int i, r;
 
        for (i = 0; i < adev->num_ip_blocks; i++) {
-               if (!adev->ip_block_enabled[i])
+               if (!adev->ip_block_status[i].valid)
                        continue;
                r = adev->ip_blocks[i].funcs->resume(adev);
                if (r)
@@ -1577,8 +1588,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
        amdgpu_fence_driver_fini(adev);
        amdgpu_fbdev_fini(adev);
        r = amdgpu_fini(adev);
-       kfree(adev->ip_block_enabled);
-       adev->ip_block_enabled = NULL;
+       kfree(adev->ip_block_status);
+       adev->ip_block_status = NULL;
        adev->accel_working = false;
        /* free i2c buses */
        amdgpu_i2c_fini(adev);
index 975edb1000a202e3dcd2b7cbe2cc2c8916aa855f..4afc507820c01db355600631e67f98a3e5d4a644 100644 (file)
@@ -352,7 +352,7 @@ unsigned long amdgpu_gem_timeout(uint64_t timeout_ns)
        if (((int64_t)timeout_ns) < 0)
                return MAX_SCHEDULE_TIMEOUT;
 
-       timeout = ktime_sub_ns(ktime_get(), timeout_ns);
+       timeout = ktime_sub(ns_to_ktime(timeout_ns), ktime_get());
        if (ktime_to_ns(timeout) < 0)
                return 0;
 
@@ -449,7 +449,7 @@ out:
  * vital here, so they are not reported back to userspace.
  */
 static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
-                                   struct amdgpu_bo_va *bo_va)
+                                   struct amdgpu_bo_va *bo_va, uint32_t operation)
 {
        struct ttm_validate_buffer tv, *entry;
        struct amdgpu_bo_list_entry *vm_bos;
@@ -485,7 +485,9 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
        if (r)
                goto error_unlock;
 
-       r = amdgpu_vm_bo_update(adev, bo_va, &bo_va->bo->tbo.mem);
+
+       if (operation == AMDGPU_VA_OP_MAP)
+               r = amdgpu_vm_bo_update(adev, bo_va, &bo_va->bo->tbo.mem);
 
 error_unlock:
        mutex_unlock(&bo_va->vm->mutex);
@@ -580,7 +582,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
        }
 
        if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
-               amdgpu_gem_va_update_vm(adev, bo_va);
+               amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
 
        drm_gem_object_unreference_unlocked(gobj);
        return r;
index 52dff75aac6f3e5c3ac04252ec19c122bace0558..bc0fac618a3f01121edb740207b9866b6818f71f 100644 (file)
@@ -180,16 +180,16 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
        if (vm) {
                /* do context switch */
                amdgpu_vm_flush(ring, vm, ib->sync.last_vm_update);
-       }
 
-       if (vm && ring->funcs->emit_gds_switch)
-               amdgpu_ring_emit_gds_switch(ring, ib->vm->ids[ring->idx].id,
-                                           ib->gds_base, ib->gds_size,
-                                           ib->gws_base, ib->gws_size,
-                                           ib->oa_base, ib->oa_size);
+               if (ring->funcs->emit_gds_switch)
+                       amdgpu_ring_emit_gds_switch(ring, ib->vm->ids[ring->idx].id,
+                                                   ib->gds_base, ib->gds_size,
+                                                   ib->gws_base, ib->gws_size,
+                                                   ib->oa_base, ib->oa_size);
 
-       if (ring->funcs->emit_hdp_flush)
-               amdgpu_ring_emit_hdp_flush(ring);
+               if (ring->funcs->emit_hdp_flush)
+                       amdgpu_ring_emit_hdp_flush(ring);
+       }
 
        old_ctx = ring->current_ctx;
        for (i = 0; i < num_ibs; ++i) {
index 5533434c7a8fad8dd22bab138c84236befe13167..3bfe67de834904628e0e4e11677c706c4848fde7 100644 (file)
@@ -235,7 +235,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
 
                for (i = 0; i < adev->num_ip_blocks; i++) {
                        if (adev->ip_blocks[i].type == type &&
-                           adev->ip_block_enabled[i]) {
+                           adev->ip_block_status[i].valid) {
                                ip.hw_ip_version_major = adev->ip_blocks[i].major;
                                ip.hw_ip_version_minor = adev->ip_blocks[i].minor;
                                ip.capabilities_flags = 0;
@@ -274,7 +274,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
 
                for (i = 0; i < adev->num_ip_blocks; i++)
                        if (adev->ip_blocks[i].type == type &&
-                           adev->ip_block_enabled[i] &&
+                           adev->ip_block_status[i].valid &&
                            count < AMDGPU_HW_IP_INSTANCE_MAX_COUNT)
                                count++;
 
@@ -317,16 +317,17 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        break;
                case AMDGPU_INFO_FW_GFX_RLC:
                        fw_info.ver = adev->gfx.rlc_fw_version;
-                       fw_info.feature = 0;
+                       fw_info.feature = adev->gfx.rlc_feature_version;
                        break;
                case AMDGPU_INFO_FW_GFX_MEC:
-                       if (info->query_fw.index == 0)
+                       if (info->query_fw.index == 0) {
                                fw_info.ver = adev->gfx.mec_fw_version;
-                       else if (info->query_fw.index == 1)
+                               fw_info.feature = adev->gfx.mec_feature_version;
+                       } else if (info->query_fw.index == 1) {
                                fw_info.ver = adev->gfx.mec2_fw_version;
-                       else
+                               fw_info.feature = adev->gfx.mec2_feature_version;
+                       } else
                                return -EINVAL;
-                       fw_info.feature = 0;
                        break;
                case AMDGPU_INFO_FW_SMC:
                        fw_info.ver = adev->pm.fw_version;
@@ -336,7 +337,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                        if (info->query_fw.index >= 2)
                                return -EINVAL;
                        fw_info.ver = adev->sdma[info->query_fw.index].fw_version;
-                       fw_info.feature = 0;
+                       fw_info.feature = adev->sdma[info->query_fw.index].feature_version;
                        break;
                default:
                        return -EINVAL;
@@ -416,7 +417,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                return n ? -EFAULT : 0;
        }
        case AMDGPU_INFO_DEV_INFO: {
-               struct drm_amdgpu_info_device dev_info;
+               struct drm_amdgpu_info_device dev_info = {};
                struct amdgpu_cu_info cu_info;
 
                dev_info.device_id = dev->pdev->device;
@@ -459,6 +460,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                memcpy(&dev_info.cu_bitmap[0], &cu_info.bitmap[0], sizeof(cu_info.bitmap));
                dev_info.vram_type = adev->mc.vram_type;
                dev_info.vram_bit_width = adev->mc.vram_width;
+               dev_info.vce_harvest_config = adev->vce.harvest_config;
 
                return copy_to_user(out, &dev_info,
                                    min((size_t)size, sizeof(dev_info))) ? -EFAULT : 0;
index 2f7a5efa21c23ab0fda25ee0ebbb360efae966ea..f5c22556ec2c17ff145c48440dfe5e3563e67606 100644 (file)
@@ -374,7 +374,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
        unsigned height_in_mb = ALIGN(height / 16, 2);
        unsigned fs_in_mb = width_in_mb * height_in_mb;
 
-       unsigned image_size, tmp, min_dpb_size, num_dpb_buffer;
+       unsigned image_size, tmp, min_dpb_size, num_dpb_buffer, min_ctx_size;
 
        image_size = width * height;
        image_size += image_size / 2;
@@ -466,6 +466,8 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
 
                num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
                min_dpb_size = image_size * num_dpb_buffer;
+               min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16)
+                                          * 16 * num_dpb_buffer + 52 * 1024;
                break;
 
        default:
@@ -486,6 +488,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
 
        buf_sizes[0x1] = dpb_size;
        buf_sizes[0x2] = image_size;
+       buf_sizes[0x4] = min_ctx_size;
        return 0;
 }
 
@@ -628,6 +631,13 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
                        return -EINVAL;
                }
 
+       } else if (cmd == 0x206) {
+               if ((end - start) < ctx->buf_sizes[4]) {
+                       DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
+                                         (unsigned)(end - start),
+                                         ctx->buf_sizes[4]);
+                       return -EINVAL;
+               }
        } else if ((cmd != 0x100) && (cmd != 0x204)) {
                DRM_ERROR("invalid UVD command %X!\n", cmd);
                return -EINVAL;
@@ -755,9 +765,10 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)
        struct amdgpu_uvd_cs_ctx ctx = {};
        unsigned buf_sizes[] = {
                [0x00000000]    =       2048,
-               [0x00000001]    =       32 * 1024 * 1024,
-               [0x00000002]    =       2048 * 1152 * 3,
+               [0x00000001]    =       0xFFFFFFFF,
+               [0x00000002]    =       0xFFFFFFFF,
                [0x00000003]    =       2048,
+               [0x00000004]    =       0xFFFFFFFF,
        };
        struct amdgpu_ib *ib = &parser->ibs[ib_idx];
        int r;
index ab83cc1ca4cc04865b0bf918c410a4351496fb22..15df46c93f0a3d9e0810b9018ba761bfaa2cc418 100644 (file)
@@ -500,6 +500,7 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev)
                amdgpu_ucode_print_sdma_hdr(&hdr->header);
                fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
                adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
                fw_data = (const __le32 *)
                        (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
                WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0);
index f75a31df30bdb704f93e5dd465a3a74d93b524d8..ace870afc7d45154a6bb6013cb45b773a8e63512 100644 (file)
@@ -494,29 +494,67 @@ static void cz_dpm_fini(struct amdgpu_device *adev)
        amdgpu_free_extended_power_table(adev);
 }
 
+#define ixSMUSVI_NB_CURRENTVID 0xD8230044
+#define CURRENT_NB_VID_MASK 0xff000000
+#define CURRENT_NB_VID__SHIFT 24
+#define ixSMUSVI_GFX_CURRENTVID  0xD8230048
+#define CURRENT_GFX_VID_MASK 0xff000000
+#define CURRENT_GFX_VID__SHIFT 24
+
 static void
 cz_dpm_debugfs_print_current_performance_level(struct amdgpu_device *adev,
                                               struct seq_file *m)
 {
+       struct cz_power_info *pi = cz_get_pi(adev);
        struct amdgpu_clock_voltage_dependency_table *table =
                &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
-       u32 current_index =
-               (RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX) &
-               TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX_MASK) >>
-               TARGET_AND_CURRENT_PROFILE_INDEX__CURR_SCLK_INDEX__SHIFT;
-       u32 sclk, tmp;
-       u16 vddc;
-
-       if (current_index >= NUM_SCLK_LEVELS) {
-               seq_printf(m, "invalid dpm profile %d\n", current_index);
+       struct amdgpu_uvd_clock_voltage_dependency_table *uvd_table =
+               &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+       struct amdgpu_vce_clock_voltage_dependency_table *vce_table =
+               &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
+       u32 sclk_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX),
+                                      TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
+       u32 uvd_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+                                     TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
+       u32 vce_index = REG_GET_FIELD(RREG32_SMC(ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
+                                     TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
+       u32 sclk, vclk, dclk, ecclk, tmp;
+       u16 vddnb, vddgfx;
+
+       if (sclk_index >= NUM_SCLK_LEVELS) {
+               seq_printf(m, "invalid sclk dpm profile %d\n", sclk_index);
        } else {
-               sclk = table->entries[current_index].clk;
-               tmp = (RREG32_SMC(ixSMU_VOLTAGE_STATUS) &
-                       SMU_VOLTAGE_STATUS__SMU_VOLTAGE_CURRENT_LEVEL_MASK) >>
-                       SMU_VOLTAGE_STATUS__SMU_VOLTAGE_CURRENT_LEVEL__SHIFT;
-               vddc = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
-               seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
-                          current_index, sclk, vddc);
+               sclk = table->entries[sclk_index].clk;
+               seq_printf(m, "%u sclk: %u\n", sclk_index, sclk);
+       }
+
+       tmp = (RREG32_SMC(ixSMUSVI_NB_CURRENTVID) &
+              CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
+       vddnb = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
+       tmp = (RREG32_SMC(ixSMUSVI_GFX_CURRENTVID) &
+              CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
+       vddgfx = cz_convert_8bit_index_to_voltage(adev, (u16)tmp);
+       seq_printf(m, "vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
+
+       seq_printf(m, "uvd    %sabled\n", pi->uvd_power_gated ? "dis" : "en");
+       if (!pi->uvd_power_gated) {
+               if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                       seq_printf(m, "invalid uvd dpm level %d\n", uvd_index);
+               } else {
+                       vclk = uvd_table->entries[uvd_index].vclk;
+                       dclk = uvd_table->entries[uvd_index].dclk;
+                       seq_printf(m, "%u uvd vclk: %u dclk: %u\n", uvd_index, vclk, dclk);
+               }
+       }
+
+       seq_printf(m, "vce    %sabled\n", pi->vce_power_gated ? "dis" : "en");
+       if (!pi->vce_power_gated) {
+               if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
+                       seq_printf(m, "invalid vce dpm level %d\n", vce_index);
+               } else {
+                       ecclk = vce_table->entries[vce_index].ecclk;
+                       seq_printf(m, "%u vce ecclk: %u\n", vce_index, ecclk);
+               }
        }
 }
 
@@ -1679,25 +1717,31 @@ static int cz_dpm_unforce_dpm_levels(struct amdgpu_device *adev)
        if (ret)
                return ret;
 
-       DRM_INFO("DPM unforce state min=%d, max=%d.\n",
-                       pi->sclk_dpm.soft_min_clk,
-                       pi->sclk_dpm.soft_max_clk);
+       DRM_DEBUG("DPM unforce state min=%d, max=%d.\n",
+                 pi->sclk_dpm.soft_min_clk,
+                 pi->sclk_dpm.soft_max_clk);
 
        return 0;
 }
 
 static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
-                               enum amdgpu_dpm_forced_level level)
+                                 enum amdgpu_dpm_forced_level level)
 {
        int ret = 0;
 
        switch (level) {
        case AMDGPU_DPM_FORCED_LEVEL_HIGH:
+               ret = cz_dpm_unforce_dpm_levels(adev);
+               if (ret)
+                       return ret;
                ret = cz_dpm_force_highest(adev);
                if (ret)
                        return ret;
                break;
        case AMDGPU_DPM_FORCED_LEVEL_LOW:
+               ret = cz_dpm_unforce_dpm_levels(adev);
+               if (ret)
+                       return ret;
                ret = cz_dpm_force_lowest(adev);
                if (ret)
                        return ret;
@@ -1711,6 +1755,8 @@ static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
                break;
        }
 
+       adev->pm.dpm.forced_level = level;
+
        return ret;
 }
 
index 5cde635978f940ff250ffb22a52c77a0db38ea26..e70a26f587a03f7dde6788f88add8f32a25ad764 100644 (file)
@@ -2632,6 +2632,7 @@ static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_device *dev = crtc->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -2640,6 +2641,9 @@ static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
                dce_v10_0_vga_enable(crtc, true);
                amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
                dce_v10_0_vga_enable(crtc, false);
+               /* Make sure VBLANK interrupt is still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
                drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
                dce_v10_0_crtc_load_lut(crtc);
                break;
@@ -3403,19 +3407,25 @@ static int dce_v10_0_crtc_irq(struct amdgpu_device *adev,
 
        switch (entry->src_data) {
        case 0: /* vblank */
-               if (disp_int & interrupt_status_offsets[crtc].vblank) {
+               if (disp_int & interrupt_status_offsets[crtc].vblank)
                        dce_v10_0_crtc_vblank_int_ack(adev, crtc);
-                       if (amdgpu_irq_enabled(adev, source, irq_type)) {
-                               drm_handle_vblank(adev->ddev, crtc);
-                       }
-                       DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               if (amdgpu_irq_enabled(adev, source, irq_type)) {
+                       drm_handle_vblank(adev->ddev, crtc);
                }
+               DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+
                break;
        case 1: /* vline */
-               if (disp_int & interrupt_status_offsets[crtc].vline) {
+               if (disp_int & interrupt_status_offsets[crtc].vline)
                        dce_v10_0_crtc_vline_int_ack(adev, crtc);
-                       DRM_DEBUG("IH: D%d vline\n", crtc + 1);
-               }
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               DRM_DEBUG("IH: D%d vline\n", crtc + 1);
+
                break;
        default:
                DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
index 95efd98b202d5d74e7329b009e944dd7f8bdcfab..dcb402ee048a602ecf03aade115a872212781811 100644 (file)
@@ -2631,6 +2631,7 @@ static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_device *dev = crtc->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -2639,6 +2640,9 @@ static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)
                dce_v11_0_vga_enable(crtc, true);
                amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
                dce_v11_0_vga_enable(crtc, false);
+               /* Make sure VBLANK interrupt is still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
                drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
                dce_v11_0_crtc_load_lut(crtc);
                break;
@@ -3402,19 +3406,25 @@ static int dce_v11_0_crtc_irq(struct amdgpu_device *adev,
 
        switch (entry->src_data) {
        case 0: /* vblank */
-               if (disp_int & interrupt_status_offsets[crtc].vblank) {
+               if (disp_int & interrupt_status_offsets[crtc].vblank)
                        dce_v11_0_crtc_vblank_int_ack(adev, crtc);
-                       if (amdgpu_irq_enabled(adev, source, irq_type)) {
-                               drm_handle_vblank(adev->ddev, crtc);
-                       }
-                       DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               if (amdgpu_irq_enabled(adev, source, irq_type)) {
+                       drm_handle_vblank(adev->ddev, crtc);
                }
+               DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+
                break;
        case 1: /* vline */
-               if (disp_int & interrupt_status_offsets[crtc].vline) {
+               if (disp_int & interrupt_status_offsets[crtc].vline)
                        dce_v11_0_crtc_vline_int_ack(adev, crtc);
-                       DRM_DEBUG("IH: D%d vline\n", crtc + 1);
-               }
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               DRM_DEBUG("IH: D%d vline\n", crtc + 1);
+
                break;
        default:
                DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
index aaca8d663f2c60e97921e0c06a69a1c7a4549322..cc050a329c496e66d44e481662acf4252e5e56ef 100644 (file)
@@ -2566,6 +2566,7 @@ static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode)
        struct drm_device *dev = crtc->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       unsigned type;
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -2574,6 +2575,9 @@ static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode)
                dce_v8_0_vga_enable(crtc, true);
                amdgpu_atombios_crtc_blank(crtc, ATOM_DISABLE);
                dce_v8_0_vga_enable(crtc, false);
+               /* Make sure VBLANK interrupt is still enabled */
+               type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id);
+               amdgpu_irq_update(adev, &adev->crtc_irq, type);
                drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id);
                dce_v8_0_crtc_load_lut(crtc);
                break;
@@ -3237,19 +3241,25 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev,
 
        switch (entry->src_data) {
        case 0: /* vblank */
-               if (disp_int & interrupt_status_offsets[crtc].vblank) {
+               if (disp_int & interrupt_status_offsets[crtc].vblank)
                        WREG32(mmLB_VBLANK_STATUS + crtc_offsets[crtc], LB_VBLANK_STATUS__VBLANK_ACK_MASK);
-                       if (amdgpu_irq_enabled(adev, source, irq_type)) {
-                               drm_handle_vblank(adev->ddev, crtc);
-                       }
-                       DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               if (amdgpu_irq_enabled(adev, source, irq_type)) {
+                       drm_handle_vblank(adev->ddev, crtc);
                }
+               DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
+
                break;
        case 1: /* vline */
-               if (disp_int & interrupt_status_offsets[crtc].vline) {
+               if (disp_int & interrupt_status_offsets[crtc].vline)
                        WREG32(mmLB_VLINE_STATUS + crtc_offsets[crtc], LB_VLINE_STATUS__VLINE_ACK_MASK);
-                       DRM_DEBUG("IH: D%d vline\n", crtc + 1);
-               }
+               else
+                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+               DRM_DEBUG("IH: D%d vline\n", crtc + 1);
+
                break;
        default:
                DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data);
index 2c188fb9fd22ff1a3528673beb8866639d5ef631..0d8bf2cb195603b8be90346a58eabfee62670d23 100644 (file)
@@ -2561,7 +2561,7 @@ static bool gfx_v7_0_ring_emit_semaphore(struct amdgpu_ring *ring,
  * sheduling on the ring.  This function schedules the IB
  * on the gfx ring for execution by the GPU.
  */
-static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
+static void gfx_v7_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
                                  struct amdgpu_ib *ib)
 {
        bool need_ctx_switch = ring->current_ctx != ib->ctx;
@@ -2569,15 +2569,10 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        u32 next_rptr = ring->wptr + 5;
 
        /* drop the CE preamble IB for the same context */
-       if ((ring->type == AMDGPU_RING_TYPE_GFX) &&
-           (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
-           !need_ctx_switch)
+       if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) && !need_ctx_switch)
                return;
 
-       if (ring->type == AMDGPU_RING_TYPE_COMPUTE)
-               control |= INDIRECT_BUFFER_VALID;
-
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
+       if (need_ctx_switch)
                next_rptr += 2;
 
        next_rptr += 4;
@@ -2588,7 +2583,7 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, next_rptr);
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
+       if (need_ctx_switch) {
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
                amdgpu_ring_write(ring, 0);
        }
@@ -2611,6 +2606,35 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, control);
 }
 
+static void gfx_v7_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+                                 struct amdgpu_ib *ib)
+{
+       u32 header, control = 0;
+       u32 next_rptr = ring->wptr + 5;
+
+       control |= INDIRECT_BUFFER_VALID;
+       next_rptr += 4;
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, WRITE_DATA_DST_SEL(5) | WR_CONFIRM);
+       amdgpu_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+       amdgpu_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+       amdgpu_ring_write(ring, next_rptr);
+
+       header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+
+       control |= ib->length_dw |
+                          (ib->vm ? (ib->vm->ids[ring->idx].id << 24) : 0);
+
+       amdgpu_ring_write(ring, header);
+       amdgpu_ring_write(ring,
+#ifdef __BIG_ENDIAN
+                                         (2 << 0) |
+#endif
+                                         (ib->gpu_addr & 0xFFFFFFFC));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+       amdgpu_ring_write(ring, control);
+}
+
 /**
  * gfx_v7_0_ring_test_ib - basic ring IB test
  *
@@ -3056,6 +3080,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
        mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
        amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
        adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
+       adev->gfx.mec_feature_version = le32_to_cpu(
+                                       mec_hdr->ucode_feature_version);
 
        gfx_v7_0_cp_compute_enable(adev, false);
 
@@ -3078,6 +3104,8 @@ static int gfx_v7_0_cp_compute_load_microcode(struct amdgpu_device *adev)
                mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
                amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
                adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
+               adev->gfx.mec2_feature_version = le32_to_cpu(
+                               mec2_hdr->ucode_feature_version);
 
                /* MEC2 */
                fw_data = (const __le32 *)
@@ -4042,6 +4070,8 @@ static int gfx_v7_0_rlc_resume(struct amdgpu_device *adev)
        hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
        amdgpu_ucode_print_rlc_hdr(&hdr->header);
        adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(
+                                       hdr->ucode_feature_version);
 
        gfx_v7_0_rlc_stop(adev);
 
@@ -5098,7 +5128,7 @@ static void gfx_v7_0_print_status(void *handle)
                dev_info(adev->dev, "  CP_HPD_EOP_CONTROL=0x%08X\n",
                         RREG32(mmCP_HPD_EOP_CONTROL));
 
-               for (queue = 0; queue < 8; i++) {
+               for (queue = 0; queue < 8; queue++) {
                        cik_srbm_select(adev, me, pipe, queue, 0);
                        dev_info(adev->dev, "  queue: %d\n", queue);
                        dev_info(adev->dev, "  CP_PQ_WPTR_POLL_CNTL=0x%08X\n",
@@ -5555,7 +5585,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = {
        .get_wptr = gfx_v7_0_ring_get_wptr_gfx,
        .set_wptr = gfx_v7_0_ring_set_wptr_gfx,
        .parse_cs = NULL,
-       .emit_ib = gfx_v7_0_ring_emit_ib,
+       .emit_ib = gfx_v7_0_ring_emit_ib_gfx,
        .emit_fence = gfx_v7_0_ring_emit_fence_gfx,
        .emit_semaphore = gfx_v7_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v7_0_ring_emit_vm_flush,
@@ -5571,7 +5601,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = {
        .get_wptr = gfx_v7_0_ring_get_wptr_compute,
        .set_wptr = gfx_v7_0_ring_set_wptr_compute,
        .parse_cs = NULL,
-       .emit_ib = gfx_v7_0_ring_emit_ib,
+       .emit_ib = gfx_v7_0_ring_emit_ib_compute,
        .emit_fence = gfx_v7_0_ring_emit_fence_compute,
        .emit_semaphore = gfx_v7_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v7_0_ring_emit_vm_flush,
index 7b683fb2173c728fff760c926f1204b3897b4eae..20e2cfd521d5352202070f357de89234175cb800 100644 (file)
@@ -587,6 +587,7 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        int err;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct gfx_firmware_header_v1_0 *cp_hdr;
 
        DRM_DEBUG("\n");
 
@@ -611,6 +612,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
+       adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
        err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
@@ -619,6 +623,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.me_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
+       adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
        err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
@@ -627,12 +634,18 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.ce_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
+       adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
        err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
        if (err)
                goto out;
        err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
+       adev->gfx.rlc_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.rlc_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
        err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
@@ -641,6 +654,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        err = amdgpu_ucode_validate(adev->gfx.mec_fw);
        if (err)
                goto out;
+       cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
+       adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
+       adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
        snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
        err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
@@ -648,6 +664,12 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
                if (err)
                        goto out;
+               cp_hdr = (const struct gfx_firmware_header_v1_0 *)
+                                               adev->gfx.mec2_fw->data;
+               adev->gfx.mec2_fw_version = le32_to_cpu(
+                                               cp_hdr->header.ucode_version);
+               adev->gfx.mec2_feature_version = le32_to_cpu(
+                                               cp_hdr->ucode_feature_version);
        } else {
                err = 0;
                adev->gfx.mec2_fw = NULL;
@@ -1813,10 +1835,7 @@ static u32 gfx_v8_0_get_rb_disabled(struct amdgpu_device *adev,
        u32 data, mask;
 
        data = RREG32(mmCC_RB_BACKEND_DISABLE);
-       if (data & 1)
-               data &= CC_RB_BACKEND_DISABLE__BACKEND_DISABLE_MASK;
-       else
-               data = 0;
+       data &= CC_RB_BACKEND_DISABLE__BACKEND_DISABLE_MASK;
 
        data |= RREG32(mmGC_USER_RB_BACKEND_DISABLE);
 
@@ -1986,6 +2005,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                adev->gfx.config.max_shader_engines = 1;
                adev->gfx.config.max_tile_pipes = 2;
                adev->gfx.config.max_sh_per_se = 1;
+               adev->gfx.config.max_backends_per_se = 2;
 
                switch (adev->pdev->revision) {
                case 0xc4:
@@ -1994,7 +2014,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                case 0xcc:
                        /* B10 */
                        adev->gfx.config.max_cu_per_sh = 8;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc5:
                case 0x81:
@@ -2003,14 +2022,12 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                case 0xcd:
                        /* B8 */
                        adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc6:
                case 0xca:
                case 0xce:
                        /* B6 */
                        adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
                        break;
                case 0xc7:
                case 0x87:
@@ -2018,7 +2035,6 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev)
                default:
                        /* B4 */
                        adev->gfx.config.max_cu_per_sh = 4;
-                       adev->gfx.config.max_backends_per_se = 1;
                        break;
                }
 
@@ -2278,7 +2294,6 @@ static int gfx_v8_0_rlc_load_microcode(struct amdgpu_device *adev)
 
        hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
        amdgpu_ucode_print_rlc_hdr(&hdr->header);
-       adev->gfx.rlc_fw_version = le32_to_cpu(hdr->header.ucode_version);
 
        fw_data = (const __le32 *)(adev->gfx.rlc_fw->data +
                           le32_to_cpu(hdr->header.ucode_array_offset_bytes));
@@ -2364,12 +2379,6 @@ static int gfx_v8_0_cp_gfx_load_microcode(struct amdgpu_device *adev)
        amdgpu_ucode_print_gfx_hdr(&pfp_hdr->header);
        amdgpu_ucode_print_gfx_hdr(&ce_hdr->header);
        amdgpu_ucode_print_gfx_hdr(&me_hdr->header);
-       adev->gfx.pfp_fw_version = le32_to_cpu(pfp_hdr->header.ucode_version);
-       adev->gfx.ce_fw_version = le32_to_cpu(ce_hdr->header.ucode_version);
-       adev->gfx.me_fw_version = le32_to_cpu(me_hdr->header.ucode_version);
-       adev->gfx.me_feature_version = le32_to_cpu(me_hdr->ucode_feature_version);
-       adev->gfx.ce_feature_version = le32_to_cpu(ce_hdr->ucode_feature_version);
-       adev->gfx.pfp_feature_version = le32_to_cpu(pfp_hdr->ucode_feature_version);
 
        gfx_v8_0_cp_gfx_enable(adev, false);
 
@@ -2625,7 +2634,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 
        mec_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
        amdgpu_ucode_print_gfx_hdr(&mec_hdr->header);
-       adev->gfx.mec_fw_version = le32_to_cpu(mec_hdr->header.ucode_version);
 
        fw_data = (const __le32 *)
                (adev->gfx.mec_fw->data +
@@ -2644,7 +2652,6 @@ static int gfx_v8_0_cp_compute_load_microcode(struct amdgpu_device *adev)
 
                mec2_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
                amdgpu_ucode_print_gfx_hdr(&mec2_hdr->header);
-               adev->gfx.mec2_fw_version = le32_to_cpu(mec2_hdr->header.ucode_version);
 
                fw_data = (const __le32 *)
                        (adev->gfx.mec2_fw->data +
@@ -3128,7 +3135,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev)
                                WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
                                       AMDGPU_DOORBELL_KIQ << 2);
                                WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
-                                               0x7FFFF << 2);
+                                      AMDGPU_DOORBELL_MEC_RING7 << 2);
                        }
                        tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL);
                        tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL,
@@ -3756,7 +3763,7 @@ static void gfx_v8_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
        amdgpu_ring_write(ring, 0x20); /* poll interval */
 }
 
-static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
+static void gfx_v8_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
                                  struct amdgpu_ib *ib)
 {
        bool need_ctx_switch = ring->current_ctx != ib->ctx;
@@ -3764,15 +3771,10 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        u32 next_rptr = ring->wptr + 5;
 
        /* drop the CE preamble IB for the same context */
-       if ((ring->type == AMDGPU_RING_TYPE_GFX) &&
-           (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
-           !need_ctx_switch)
+       if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) && !need_ctx_switch)
                return;
 
-       if (ring->type == AMDGPU_RING_TYPE_COMPUTE)
-               control |= INDIRECT_BUFFER_VALID;
-
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
+       if (need_ctx_switch)
                next_rptr += 2;
 
        next_rptr += 4;
@@ -3783,7 +3785,7 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, next_rptr);
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
+       if (need_ctx_switch) {
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
                amdgpu_ring_write(ring, 0);
        }
@@ -3806,6 +3808,36 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, control);
 }
 
+static void gfx_v8_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+                                 struct amdgpu_ib *ib)
+{
+       u32 header, control = 0;
+       u32 next_rptr = ring->wptr + 5;
+
+       control |= INDIRECT_BUFFER_VALID;
+
+       next_rptr += 4;
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+       amdgpu_ring_write(ring, WRITE_DATA_DST_SEL(5) | WR_CONFIRM);
+       amdgpu_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+       amdgpu_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+       amdgpu_ring_write(ring, next_rptr);
+
+       header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+
+       control |= ib->length_dw |
+                          (ib->vm ? (ib->vm->ids[ring->idx].id << 24) : 0);
+
+       amdgpu_ring_write(ring, header);
+       amdgpu_ring_write(ring,
+#ifdef __BIG_ENDIAN
+                                         (2 << 0) |
+#endif
+                                         (ib->gpu_addr & 0xFFFFFFFC));
+       amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+       amdgpu_ring_write(ring, control);
+}
+
 static void gfx_v8_0_ring_emit_fence_gfx(struct amdgpu_ring *ring, u64 addr,
                                         u64 seq, unsigned flags)
 {
@@ -4227,7 +4259,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = {
        .get_wptr = gfx_v8_0_ring_get_wptr_gfx,
        .set_wptr = gfx_v8_0_ring_set_wptr_gfx,
        .parse_cs = NULL,
-       .emit_ib = gfx_v8_0_ring_emit_ib,
+       .emit_ib = gfx_v8_0_ring_emit_ib_gfx,
        .emit_fence = gfx_v8_0_ring_emit_fence_gfx,
        .emit_semaphore = gfx_v8_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v8_0_ring_emit_vm_flush,
@@ -4243,7 +4275,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = {
        .get_wptr = gfx_v8_0_ring_get_wptr_compute,
        .set_wptr = gfx_v8_0_ring_set_wptr_compute,
        .parse_cs = NULL,
-       .emit_ib = gfx_v8_0_ring_emit_ib,
+       .emit_ib = gfx_v8_0_ring_emit_ib_compute,
        .emit_fence = gfx_v8_0_ring_emit_fence_compute,
        .emit_semaphore = gfx_v8_0_ring_emit_semaphore,
        .emit_vm_flush = gfx_v8_0_ring_emit_vm_flush,
index d7895885fe0cf3b3e7cd5d1ae52f291053420b17..a988dfb1d3942e9246361bfd7b97bdabc5e5286c 100644 (file)
@@ -121,6 +121,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
        int err, i;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct sdma_firmware_header_v1_0 *hdr;
 
        DRM_DEBUG("\n");
 
@@ -142,6 +143,9 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->sdma[i].fw);
                if (err)
                        goto out;
+               hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
 
                if (adev->firmware.smu_load) {
                        info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -541,8 +545,6 @@ static int sdma_v2_4_load_microcode(struct amdgpu_device *adev)
                        hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
                        amdgpu_ucode_print_sdma_hdr(&hdr->header);
                        fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-                       adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
                        fw_data = (const __le32 *)
                                (adev->sdma[i].fw->data +
                                 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
index 7bb37b93993fb5312eb2d46189bf09bf789c3989..2b86569b18d3656c87975175a1ff771599c958d6 100644 (file)
@@ -159,6 +159,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
        int err, i;
        struct amdgpu_firmware_info *info = NULL;
        const struct common_firmware_header *header = NULL;
+       const struct sdma_firmware_header_v1_0 *hdr;
 
        DRM_DEBUG("\n");
 
@@ -183,6 +184,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
                err = amdgpu_ucode_validate(adev->sdma[i].fw);
                if (err)
                        goto out;
+               hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
+               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
+               adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version);
 
                if (adev->firmware.smu_load) {
                        info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i];
@@ -630,8 +634,6 @@ static int sdma_v3_0_load_microcode(struct amdgpu_device *adev)
                hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data;
                amdgpu_ucode_print_sdma_hdr(&hdr->header);
                fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4;
-               adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version);
-
                fw_data = (const __le32 *)
                        (adev->sdma[i].fw->data +
                                le32_to_cpu(hdr->header.ucode_array_offset_bytes));
index d62c4002e39cc7acc5a3427d0aed92bedf12c984..d1064ca3670ec31376293950c76452414e94ff23 100644 (file)
@@ -35,6 +35,8 @@
 #include "oss/oss_2_0_d.h"
 #include "oss/oss_2_0_sh_mask.h"
 #include "gca/gfx_8_0_d.h"
+#include "smu/smu_7_1_2_d.h"
+#include "smu/smu_7_1_2_sh_mask.h"
 
 #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT    0x04
 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK      0x10
@@ -112,6 +114,10 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
 
        mutex_lock(&adev->grbm_idx_mutex);
        for (idx = 0; idx < 2; ++idx) {
+
+               if (adev->vce.harvest_config & (1 << idx))
+                       continue;
+
                if(idx == 0)
                        WREG32_P(mmGRBM_GFX_INDEX, 0,
                                ~GRBM_GFX_INDEX__VCE_INSTANCE_MASK);
@@ -190,10 +196,52 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
        return 0;
 }
 
+#define ixVCE_HARVEST_FUSE_MACRO__ADDRESS     0xC0014074
+#define VCE_HARVEST_FUSE_MACRO__SHIFT       27
+#define VCE_HARVEST_FUSE_MACRO__MASK        0x18000000
+
+static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev)
+{
+       u32 tmp;
+       unsigned ret;
+
+       if (adev->flags & AMDGPU_IS_APU)
+               tmp = (RREG32_SMC(ixVCE_HARVEST_FUSE_MACRO__ADDRESS) &
+                      VCE_HARVEST_FUSE_MACRO__MASK) >>
+                       VCE_HARVEST_FUSE_MACRO__SHIFT;
+       else
+               tmp = (RREG32_SMC(ixCC_HARVEST_FUSES) &
+                      CC_HARVEST_FUSES__VCE_DISABLE_MASK) >>
+                       CC_HARVEST_FUSES__VCE_DISABLE__SHIFT;
+
+       switch (tmp) {
+       case 1:
+               ret = AMDGPU_VCE_HARVEST_VCE0;
+               break;
+       case 2:
+               ret = AMDGPU_VCE_HARVEST_VCE1;
+               break;
+       case 3:
+               ret = AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1;
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
 static int vce_v3_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev);
+
+       if ((adev->vce.harvest_config &
+            (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1)) ==
+           (AMDGPU_VCE_HARVEST_VCE0 | AMDGPU_VCE_HARVEST_VCE1))
+               return -ENOENT;
+
        vce_v3_0_set_ring_funcs(adev);
        vce_v3_0_set_irq_funcs(adev);
 
index fa5a4448531dfe9dd307d88b55e051761821a28d..68552da4028740167ddb20289c274bc332935172 100644 (file)
@@ -122,6 +122,32 @@ static void vi_smc_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
        spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
 }
 
+/* smu_8_0_d.h */
+#define mmMP0PUB_IND_INDEX                                                      0x180
+#define mmMP0PUB_IND_DATA                                                       0x181
+
+static u32 cz_smc_rreg(struct amdgpu_device *adev, u32 reg)
+{
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       WREG32(mmMP0PUB_IND_INDEX, (reg));
+       r = RREG32(mmMP0PUB_IND_DATA);
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+       return r;
+}
+
+static void cz_smc_wreg(struct amdgpu_device *adev, u32 reg, u32 v)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&adev->smc_idx_lock, flags);
+       WREG32(mmMP0PUB_IND_INDEX, (reg));
+       WREG32(mmMP0PUB_IND_DATA, (v));
+       spin_unlock_irqrestore(&adev->smc_idx_lock, flags);
+}
+
 static u32 vi_uvd_ctx_rreg(struct amdgpu_device *adev, u32 reg)
 {
        unsigned long flags;
@@ -1222,8 +1248,13 @@ static int vi_common_early_init(void *handle)
        bool smc_enabled = false;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       adev->smc_rreg = &vi_smc_rreg;
-       adev->smc_wreg = &vi_smc_wreg;
+       if (adev->flags & AMDGPU_IS_APU) {
+               adev->smc_rreg = &cz_smc_rreg;
+               adev->smc_wreg = &cz_smc_wreg;
+       } else {
+               adev->smc_rreg = &vi_smc_rreg;
+               adev->smc_wreg = &vi_smc_wreg;
+       }
        adev->pcie_rreg = &vi_pcie_rreg;
        adev->pcie_wreg = &vi_pcie_wreg;
        adev->uvd_ctx_rreg = &vi_uvd_ctx_rreg;
index 8a1f999daa2444e613f0c61960ef3bfe31f0aa82..9be007081b72a8b5c75b4baf1fe01e92bfe792bc 100644 (file)
@@ -420,6 +420,12 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)
        pqm_uninit(&p->pqm);
 
        pdd = kfd_get_process_device_data(dev, p);
+
+       if (!pdd) {
+               mutex_unlock(&p->mutex);
+               return;
+       }
+
        if (pdd->reset_wavefronts) {
                dbgdev_wave_reset_wavefronts(pdd->dev, p);
                pdd->reset_wavefronts = false;
@@ -431,8 +437,7 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)
         * We don't call amd_iommu_unbind_pasid() here
         * because the IOMMU called us.
         */
-       if (pdd)
-               pdd->bound = false;
+       pdd->bound = false;
 
        mutex_unlock(&p->mutex);
 }
index 42d2ffa087169fd110da85e22a496aa080d34c9a..01ffe9bffe38a9e93d49a811a4803f49866a0861 100644 (file)
@@ -531,8 +531,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
 
        drm_crtc_vblank_off(crtc);
 
-       crtc->mode = *adj;
-
        val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA;
        if (val != dcrtc->dumb_ctrl) {
                dcrtc->dumb_ctrl = val;
index 580e10acaa3ace493c16305eabecd75394c6e49a..60a688ef81c71cf1174c081426c10c80e9453bdb 100644 (file)
@@ -69,8 +69,9 @@ void armada_gem_free_object(struct drm_gem_object *obj)
 
        if (dobj->obj.import_attach) {
                /* We only ever display imported data */
-               dma_buf_unmap_attachment(dobj->obj.import_attach, dobj->sgt,
-                                        DMA_TO_DEVICE);
+               if (dobj->sgt)
+                       dma_buf_unmap_attachment(dobj->obj.import_attach,
+                                                dobj->sgt, DMA_TO_DEVICE);
                drm_prime_gem_destroy(&dobj->obj, NULL);
        }
 
index c5b06fdb459c4560c46dd68a9c52314f87c319b0..e939faba7fcca8b0ff737008de124d3b7f96b3a5 100644 (file)
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
  */
 #include <drm/drmP.h>
+#include <drm/drm_plane_helper.h>
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_fb.h"
@@ -85,16 +86,8 @@ static void armada_plane_vbl(struct armada_crtc *dcrtc, void *data)
 
        if (fb)
                armada_drm_queue_unref_work(dcrtc->crtc.dev, fb);
-}
 
-static unsigned armada_limit(int start, unsigned size, unsigned max)
-{
-       int end = start + size;
-       if (end < 0)
-               return 0;
-       if (start < 0)
-               start = 0;
-       return (unsigned)end > max ? max - start : end - start;
+       wake_up(&dplane->vbl.wait);
 }
 
 static int
@@ -105,26 +98,39 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 {
        struct armada_plane *dplane = drm_to_armada_plane(plane);
        struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+       struct drm_rect src = {
+               .x1 = src_x,
+               .y1 = src_y,
+               .x2 = src_x + src_w,
+               .y2 = src_y + src_h,
+       };
+       struct drm_rect dest = {
+               .x1 = crtc_x,
+               .y1 = crtc_y,
+               .x2 = crtc_x + crtc_w,
+               .y2 = crtc_y + crtc_h,
+       };
+       const struct drm_rect clip = {
+               .x2 = crtc->mode.hdisplay,
+               .y2 = crtc->mode.vdisplay,
+       };
        uint32_t val, ctrl0;
        unsigned idx = 0;
+       bool visible;
        int ret;
 
-       crtc_w = armada_limit(crtc_x, crtc_w, dcrtc->crtc.mode.hdisplay);
-       crtc_h = armada_limit(crtc_y, crtc_h, dcrtc->crtc.mode.vdisplay);
+       ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip,
+                                           0, INT_MAX, true, false, &visible);
+       if (ret)
+               return ret;
+
        ctrl0 = CFG_DMA_FMT(drm_fb_to_armada_fb(fb)->fmt) |
                CFG_DMA_MOD(drm_fb_to_armada_fb(fb)->mod) |
                CFG_CBSH_ENA | CFG_DMA_HSMOOTH | CFG_DMA_ENA;
 
        /* Does the position/size result in nothing to display? */
-       if (crtc_w == 0 || crtc_h == 0) {
+       if (!visible)
                ctrl0 &= ~CFG_DMA_ENA;
-       }
-
-       /*
-        * FIXME: if the starting point is off screen, we need to
-        * adjust src_x, src_y, src_w, src_h appropriately, and
-        * according to the scale.
-        */
 
        if (!dcrtc->plane) {
                dcrtc->plane = plane;
@@ -134,15 +140,19 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        /* FIXME: overlay on an interlaced display */
        /* Just updating the position/size? */
        if (plane->fb == fb && dplane->ctrl0 == ctrl0) {
-               val = (src_h & 0xffff0000) | src_w >> 16;
+               val = (drm_rect_height(&src) & 0xffff0000) |
+                     drm_rect_width(&src) >> 16;
                dplane->src_hw = val;
                writel_relaxed(val, dcrtc->base + LCD_SPU_DMA_HPXL_VLN);
-               val = crtc_h << 16 | crtc_w;
+
+               val = drm_rect_height(&dest) << 16 | drm_rect_width(&dest);
                dplane->dst_hw = val;
                writel_relaxed(val, dcrtc->base + LCD_SPU_DZM_HPXL_VLN);
-               val = crtc_y << 16 | crtc_x;
+
+               val = dest.y1 << 16 | dest.x1;
                dplane->dst_yx = val;
                writel_relaxed(val, dcrtc->base + LCD_SPU_DMA_OVSA_HPXL_VLN);
+
                return 0;
        } else if (~dplane->ctrl0 & ctrl0 & CFG_DMA_ENA) {
                /* Power up the Y/U/V FIFOs on ENA 0->1 transitions */
@@ -150,15 +160,14 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                               dcrtc->base + LCD_SPU_SRAM_PARA1);
        }
 
-       ret = wait_event_timeout(dplane->vbl.wait,
-                                list_empty(&dplane->vbl.update.node),
-                                HZ/25);
-       if (ret < 0)
-               return ret;
+       wait_event_timeout(dplane->vbl.wait,
+                          list_empty(&dplane->vbl.update.node),
+                          HZ/25);
 
        if (plane->fb != fb) {
                struct armada_gem_object *obj = drm_fb_obj(fb);
-               uint32_t sy, su, sv;
+               uint32_t addr[3], pixel_format;
+               int i, num_planes, hsub;
 
                /*
                 * Take a reference on the new framebuffer - we want to
@@ -178,26 +187,39 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                                                            older_fb);
                }
 
-               src_y >>= 16;
-               src_x >>= 16;
-               sy = obj->dev_addr + fb->offsets[0] + src_y * fb->pitches[0] +
-                       src_x * fb->bits_per_pixel / 8;
-               su = obj->dev_addr + fb->offsets[1] + src_y * fb->pitches[1] +
-                       src_x;
-               sv = obj->dev_addr + fb->offsets[2] + src_y * fb->pitches[2] +
-                       src_x;
+               src_y = src.y1 >> 16;
+               src_x = src.x1 >> 16;
 
-               armada_reg_queue_set(dplane->vbl.regs, idx, sy,
+               pixel_format = fb->pixel_format;
+               hsub = drm_format_horz_chroma_subsampling(pixel_format);
+               num_planes = drm_format_num_planes(pixel_format);
+
+               /*
+                * Annoyingly, shifting a YUYV-format image by one pixel
+                * causes the U/V planes to toggle.  Toggle the UV swap.
+                * (Unfortunately, this causes momentary colour flickering.)
+                */
+               if (src_x & (hsub - 1) && num_planes == 1)
+                       ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV);
+
+               for (i = 0; i < num_planes; i++)
+                       addr[i] = obj->dev_addr + fb->offsets[i] +
+                                 src_y * fb->pitches[i] +
+                                 src_x * drm_format_plane_cpp(pixel_format, i);
+               for (; i < ARRAY_SIZE(addr); i++)
+                       addr[i] = 0;
+
+               armada_reg_queue_set(dplane->vbl.regs, idx, addr[0],
                                     LCD_SPU_DMA_START_ADDR_Y0);
-               armada_reg_queue_set(dplane->vbl.regs, idx, su,
+               armada_reg_queue_set(dplane->vbl.regs, idx, addr[1],
                                     LCD_SPU_DMA_START_ADDR_U0);
-               armada_reg_queue_set(dplane->vbl.regs, idx, sv,
+               armada_reg_queue_set(dplane->vbl.regs, idx, addr[2],
                                     LCD_SPU_DMA_START_ADDR_V0);
-               armada_reg_queue_set(dplane->vbl.regs, idx, sy,
+               armada_reg_queue_set(dplane->vbl.regs, idx, addr[0],
                                     LCD_SPU_DMA_START_ADDR_Y1);
-               armada_reg_queue_set(dplane->vbl.regs, idx, su,
+               armada_reg_queue_set(dplane->vbl.regs, idx, addr[1],
                                     LCD_SPU_DMA_START_ADDR_U1);
-               armada_reg_queue_set(dplane->vbl.regs, idx, sv,
+               armada_reg_queue_set(dplane->vbl.regs, idx, addr[2],
                                     LCD_SPU_DMA_START_ADDR_V1);
 
                val = fb->pitches[0] << 16 | fb->pitches[0];
@@ -208,24 +230,27 @@ armada_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                                     LCD_SPU_DMA_PITCH_UV);
        }
 
-       val = (src_h & 0xffff0000) | src_w >> 16;
+       val = (drm_rect_height(&src) & 0xffff0000) | drm_rect_width(&src) >> 16;
        if (dplane->src_hw != val) {
                dplane->src_hw = val;
                armada_reg_queue_set(dplane->vbl.regs, idx, val,
                                     LCD_SPU_DMA_HPXL_VLN);
        }
-       val = crtc_h << 16 | crtc_w;
+
+       val = drm_rect_height(&dest) << 16 | drm_rect_width(&dest);
        if (dplane->dst_hw != val) {
                dplane->dst_hw = val;
                armada_reg_queue_set(dplane->vbl.regs, idx, val,
                                     LCD_SPU_DZM_HPXL_VLN);
        }
-       val = crtc_y << 16 | crtc_x;
+
+       val = dest.y1 << 16 | dest.x1;
        if (dplane->dst_yx != val) {
                dplane->dst_yx = val;
                armada_reg_queue_set(dplane->vbl.regs, idx, val,
                                     LCD_SPU_DMA_OVSA_HPXL_VLN);
        }
+
        if (dplane->ctrl0 != ctrl0) {
                dplane->ctrl0 = ctrl0;
                armada_reg_queue_mod(dplane->vbl.regs, idx, ctrl0,
@@ -279,7 +304,11 @@ static int armada_plane_disable(struct drm_plane *plane)
 
 static void armada_plane_destroy(struct drm_plane *plane)
 {
-       kfree(plane);
+       struct armada_plane *dplane = drm_to_armada_plane(plane);
+
+       drm_plane_cleanup(plane);
+
+       kfree(dplane);
 }
 
 static int armada_plane_set_property(struct drm_plane *plane,
index f69b92535505b5ae1c899d6f9b08f76501851fa7..5ae5c69231280a5e1c23882289388f9ceb75a701 100644 (file)
@@ -355,6 +355,7 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
                planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
 
        drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
+       drm_crtc_vblank_reset(&crtc->base);
 
        dc->crtc = &crtc->base;
 
index 60b0c13d7ff5cc6f4c338c9ed3d7f423d684c84e..ef6182bc8e5eef229dc990354f6d31c18915f3bc 100644 (file)
@@ -313,20 +313,20 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 
        pm_runtime_enable(dev->dev);
 
-       ret = atmel_hlcdc_dc_modeset_init(dev);
+       ret = drm_vblank_init(dev, 1);
        if (ret < 0) {
-               dev_err(dev->dev, "failed to initialize mode setting\n");
+               dev_err(dev->dev, "failed to initialize vblank\n");
                goto err_periph_clk_disable;
        }
 
-       drm_mode_config_reset(dev);
-
-       ret = drm_vblank_init(dev, 1);
+       ret = atmel_hlcdc_dc_modeset_init(dev);
        if (ret < 0) {
-               dev_err(dev->dev, "failed to initialize vblank\n");
+               dev_err(dev->dev, "failed to initialize mode setting\n");
                goto err_periph_clk_disable;
        }
 
+       drm_mode_config_reset(dev);
+
        pm_runtime_get_sync(dev->dev);
        ret = drm_irq_install(dev, dc->hlcdc->irq);
        pm_runtime_put_sync(dev->dev);
@@ -559,7 +559,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
index 5b59d5ad7d1c23fc41c6d657f19367b81d1ae1de..9dcc7280e5720255baed2786ab7d8fc11554c845 100644 (file)
@@ -196,7 +196,12 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
        }
 
        funcs = connector->helper_private;
-       new_encoder = funcs->best_encoder(connector);
+
+       if (funcs->atomic_best_encoder)
+               new_encoder = funcs->atomic_best_encoder(connector,
+                                                        connector_state);
+       else
+               new_encoder = funcs->best_encoder(connector);
 
        if (!new_encoder) {
                DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
@@ -229,6 +234,9 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
                }
        }
 
+       if (WARN_ON(!connector_state->crtc))
+               return -EINVAL;
+
        connector_state->best_encoder = new_encoder;
        idx = drm_crtc_index(connector_state->crtc);
 
index b9ba06176eb1e10c6e4074a7a935a08a50313819..fed748311b928cc534f781505a37686ec7a46ba3 100644 (file)
@@ -2706,8 +2706,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       /* For some reason crtc x/y offsets are signed internally. */
-       if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
+       /*
+        * Universal plane src offsets are only 16.16, prevent havoc for
+        * drivers using universal plane code internally.
+        */
+       if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
                return -ERANGE;
 
        drm_modeset_lock_all(dev);
@@ -5395,12 +5398,9 @@ void drm_mode_config_reset(struct drm_device *dev)
                if (encoder->funcs->reset)
                        encoder->funcs->reset(encoder);
 
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               connector->status = connector_status_unknown;
-
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
                if (connector->funcs->reset)
                        connector->funcs->reset(connector);
-       }
 }
 EXPORT_SYMBOL(drm_mode_config_reset);
 
index 778bbb6425b80c9c8affddad58d993a93755c39e..eb603f1defc2250ea158864ea4371e24655138e1 100644 (file)
@@ -873,9 +873,10 @@ static void drm_dp_destroy_port(struct kref *kref)
                   from an EDID retrieval */
                if (port->connector) {
                        mutex_lock(&mgr->destroy_connector_lock);
-                       list_add(&port->connector->destroy_list, &mgr->destroy_connector_list);
+                       list_add(&port->next, &mgr->destroy_connector_list);
                        mutex_unlock(&mgr->destroy_connector_lock);
                        schedule_work(&mgr->destroy_connector_work);
+                       return;
                }
                drm_dp_port_teardown_pdt(port, port->pdt);
 
@@ -1294,7 +1295,6 @@ retry:
                                goto retry;
                        }
                        DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret);
-                       WARN(1, "fail\n");
 
                        return -EIO;
                }
@@ -2660,7 +2660,7 @@ static void drm_dp_tx_work(struct work_struct *work)
 static void drm_dp_destroy_connector_work(struct work_struct *work)
 {
        struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
-       struct drm_connector *connector;
+       struct drm_dp_mst_port *port;
 
        /*
         * Not a regular list traverse as we have to drop the destroy
@@ -2669,15 +2669,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
         */
        for (;;) {
                mutex_lock(&mgr->destroy_connector_lock);
-               connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);
-               if (!connector) {
+               port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
+               if (!port) {
                        mutex_unlock(&mgr->destroy_connector_lock);
                        break;
                }
-               list_del(&connector->destroy_list);
+               list_del(&port->next);
                mutex_unlock(&mgr->destroy_connector_lock);
 
-               mgr->cbs->destroy_connector(mgr, connector);
+               mgr->cbs->destroy_connector(mgr, port->connector);
+
+               drm_dp_port_teardown_pdt(port, port->pdt);
+
+               if (!port->input && port->vcpi.vcpi > 0)
+                       drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
+               kfree(port);
        }
 }
 
index aa8bbb460c5715a619988d6d4350b4a4507173f8..9cfcd0aef0dfacf8389407d78981b78c8c85ddf8 100644 (file)
@@ -70,6 +70,8 @@
 
 #define DRM_IOCTL_WAIT_VBLANK32                DRM_IOWR(0x3a, drm_wait_vblank32_t)
 
+#define DRM_IOCTL_MODE_ADDFB232                DRM_IOWR(0xb8, drm_mode_fb_cmd232_t)
+
 typedef struct drm_version_32 {
        int version_major;        /**< Major version */
        int version_minor;        /**< Minor version */
@@ -1016,6 +1018,63 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
        return 0;
 }
 
+typedef struct drm_mode_fb_cmd232 {
+       u32 fb_id;
+       u32 width;
+       u32 height;
+       u32 pixel_format;
+       u32 flags;
+       u32 handles[4];
+       u32 pitches[4];
+       u32 offsets[4];
+       u64 modifier[4];
+} __attribute__((packed)) drm_mode_fb_cmd232_t;
+
+static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       struct drm_mode_fb_cmd232 __user *argp = (void __user *)arg;
+       struct drm_mode_fb_cmd232 req32;
+       struct drm_mode_fb_cmd2 __user *req64;
+       int i;
+       int err;
+
+       if (copy_from_user(&req32, argp, sizeof(req32)))
+               return -EFAULT;
+
+       req64 = compat_alloc_user_space(sizeof(*req64));
+
+       if (!access_ok(VERIFY_WRITE, req64, sizeof(*req64))
+           || __put_user(req32.width, &req64->width)
+           || __put_user(req32.height, &req64->height)
+           || __put_user(req32.pixel_format, &req64->pixel_format)
+           || __put_user(req32.flags, &req64->flags))
+               return -EFAULT;
+
+       for (i = 0; i < 4; i++) {
+               if (__put_user(req32.handles[i], &req64->handles[i]))
+                       return -EFAULT;
+               if (__put_user(req32.pitches[i], &req64->pitches[i]))
+                       return -EFAULT;
+               if (__put_user(req32.offsets[i], &req64->offsets[i]))
+                       return -EFAULT;
+               if (__put_user(req32.modifier[i], &req64->modifier[i]))
+                       return -EFAULT;
+       }
+
+       err = drm_ioctl(file, DRM_IOCTL_MODE_ADDFB2, (unsigned long)req64);
+       if (err)
+               return err;
+
+       if (__get_user(req32.fb_id, &req64->fb_id))
+               return -EFAULT;
+
+       if (copy_to_user(argp, &req32, sizeof(req32)))
+               return -EFAULT;
+
+       return 0;
+}
+
 static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
        [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
@@ -1048,6 +1107,7 @@ static drm_ioctl_compat_t *drm_compat_ioctls[] = {
        [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW32)] = compat_drm_update_draw,
 #endif
        [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
+       [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB232)] = compat_drm_mode_addfb2,
 };
 
 /**
index f9cc68fbd2a3e18b076ad2ced71b8f1ddf002202..b50fa0afd9071f6c64c36de23253a2ee22ce7480 100644 (file)
@@ -75,7 +75,7 @@ module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600)
 module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
 
 static void store_vblank(struct drm_device *dev, int crtc,
-                        unsigned vblank_count_inc,
+                        u32 vblank_count_inc,
                         struct timeval *t_vblank)
 {
        struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
index 842d6b8dc3c435ee7d836402d4169847aef75d31..2a652359af644b51f257cde7528d70b6016897da 100644 (file)
@@ -1745,7 +1745,6 @@ static int fimc_probe(struct platform_device *pdev)
        spin_lock_init(&ctx->lock);
        platform_set_drvdata(pdev, ctx);
 
-       pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
        ret = exynos_drm_ippdrv_register(ippdrv);
index 8040ed2a831f9a6f226baf8aee3ce00b213be8e6..f1c6b76c127f4db02388267775431fcd25ac7eb8 100644 (file)
@@ -593,8 +593,7 @@ static int gsc_src_set_transf(struct device *dev,
 
        gsc_write(cfg, GSC_IN_CON);
 
-       ctx->rotation = cfg &
-               (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0;
+       ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
        *swap = ctx->rotation;
 
        return 0;
@@ -857,8 +856,7 @@ static int gsc_dst_set_transf(struct device *dev,
 
        gsc_write(cfg, GSC_IN_CON);
 
-       ctx->rotation = cfg &
-               (GSC_IN_ROT_90 | GSC_IN_ROT_270) ? 1 : 0;
+       ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
        *swap = ctx->rotation;
 
        return 0;
index 99e286489031c4a2931565823e0158428548aef2..4a00990e4ae4e8459b94a9a007044af1cc11af62 100644 (file)
@@ -1064,6 +1064,7 @@ static int hdmi_get_modes(struct drm_connector *connector)
 {
        struct hdmi_context *hdata = ctx_from_connector(connector);
        struct edid *edid;
+       int ret;
 
        if (!hdata->ddc_adpt)
                return -ENODEV;
@@ -1079,7 +1080,11 @@ static int hdmi_get_modes(struct drm_connector *connector)
 
        drm_mode_connector_update_edid_property(connector, edid);
 
-       return drm_add_edid_modes(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+
+       kfree(edid);
+
+       return ret;
 }
 
 static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
index cae98db3306205e2628b2090b731cf6cfdf79d4f..4706b56902b44f5ba205b30d3aa6e53678bbad52 100644 (file)
@@ -718,6 +718,10 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 
        /* handling VSYNC */
        if (val & MXR_INT_STATUS_VSYNC) {
+               /* vsync interrupt use different bit for read and clear */
+               val |= MXR_INT_CLEAR_VSYNC;
+               val &= ~MXR_INT_STATUS_VSYNC;
+
                /* interlace scan need to check shadow register */
                if (ctx->interlace) {
                        base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
@@ -743,11 +747,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 
 out:
        /* clear interrupts */
-       if (~val & MXR_INT_EN_VSYNC) {
-               /* vsync interrupt use different bit for read and clear */
-               val &= ~MXR_INT_EN_VSYNC;
-               val |= MXR_INT_CLEAR_VSYNC;
-       }
        mixer_reg_write(res, MXR_INT_STATUS, val);
 
        spin_unlock(&res->reg_slock);
@@ -907,8 +906,8 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
        }
 
        /* enable vsync interrupt */
-       mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
-                       MXR_INT_EN_VSYNC);
+       mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+       mixer_reg_writemask(res, MXR_INT_EN, ~0, MXR_INT_EN_VSYNC);
 
        return 0;
 }
@@ -918,7 +917,13 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
        struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
 
+       if (!mixer_ctx->powered) {
+               mixer_ctx->int_en &= MXR_INT_EN_VSYNC;
+               return;
+       }
+
        /* disable vsync interrupt */
+       mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
@@ -1047,6 +1052,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
 
        mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
 
+       if (ctx->int_en & MXR_INT_EN_VSYNC)
+               mixer_reg_writemask(res, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
        mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
        mixer_win_reset(ctx);
 }
index fe1599d75f14e39b2a39364b78d088d4715c368f..424228be79ae5b2aa1557ca07331e4e49e665ef8 100644 (file)
@@ -606,8 +606,6 @@ static void
 tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr,
                 uint8_t *buf, size_t size)
 {
-       buf[PB(0)] = tda998x_cksum(buf, size);
-
        reg_clear(priv, REG_DIP_IF_FLAGS, bit);
        reg_write_range(priv, addr, buf, size);
        reg_set(priv, REG_DIP_IF_FLAGS, bit);
@@ -627,6 +625,8 @@ tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
        buf[PB(4)] = p->audio_frame[4];
        buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
 
+       buf[PB(0)] = tda998x_cksum(buf, sizeof(buf));
+
        tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
                         sizeof(buf));
 }
index 542fac628b288225262289f424e92576efb7acb4..fd1de451c8c6bae13f42eaae5e9cfe572039ea18 100644 (file)
@@ -826,6 +826,7 @@ struct intel_context {
        struct kref ref;
        int user_handle;
        uint8_t remap_slice;
+       struct drm_i915_private *i915;
        struct drm_i915_file_private *file_priv;
        struct i915_ctx_hang_stats hang_stats;
        struct i915_hw_ppgtt *ppgtt;
@@ -2036,8 +2037,6 @@ struct drm_i915_gem_object {
        unsigned int cache_level:3;
        unsigned int cache_dirty:1;
 
-       unsigned int has_dma_mapping:1;
-
        unsigned int frontbuffer_bits:INTEL_FRONTBUFFER_BITS;
 
        unsigned int pin_display;
@@ -3116,7 +3115,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor);
 int i915_debugfs_connector_add(struct drm_connector *connector);
 void intel_display_crc_init(struct drm_device *dev);
 #else
-static inline int i915_debugfs_connector_add(struct drm_connector *connector) {}
+static inline int i915_debugfs_connector_add(struct drm_connector *connector)
+{ return 0; }
 static inline void intel_display_crc_init(struct drm_device *dev) {}
 #endif
 
@@ -3303,15 +3303,14 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
 #define I915_READ64(reg)       dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)
 
 #define I915_READ64_2x32(lower_reg, upper_reg) ({                      \
-               u32 upper = I915_READ(upper_reg);                       \
-               u32 lower = I915_READ(lower_reg);                       \
-               u32 tmp = I915_READ(upper_reg);                         \
-               if (upper != tmp) {                                     \
-                       upper = tmp;                                    \
-                       lower = I915_READ(lower_reg);                   \
-                       WARN_ON(I915_READ(upper_reg) != upper);         \
-               }                                                       \
-               (u64)upper << 32 | lower; })
+       u32 upper, lower, tmp;                                          \
+       tmp = I915_READ(upper_reg);                                     \
+       do {                                                            \
+               upper = tmp;                                            \
+               lower = I915_READ(lower_reg);                           \
+               tmp = I915_READ(upper_reg);                             \
+       } while (upper != tmp);                                         \
+       (u64)upper << 32 | lower; })
 
 #define POSTING_READ(reg)      (void)I915_READ_NOTRACE(reg)
 #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
index 248fd1ac7b3a04c8b866eeaba327fcd65f67c8a9..52b446b27b4d08359ce50577f53176629e323a64 100644 (file)
@@ -213,7 +213,6 @@ i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
        sg_dma_len(sg) = obj->base.size;
 
        obj->pages = st;
-       obj->has_dma_mapping = true;
        return 0;
 }
 
@@ -265,8 +264,6 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj)
 
        sg_free_table(obj->pages);
        kfree(obj->pages);
-
-       obj->has_dma_mapping = false;
 }
 
 static void
@@ -2139,6 +2136,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
                obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        }
 
+       i915_gem_gtt_finish_object(obj);
+
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_save_bit_17_swizzle(obj);
 
@@ -2199,6 +2198,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
        struct sg_page_iter sg_iter;
        struct page *page;
        unsigned long last_pfn = 0;     /* suppress gcc warning */
+       int ret;
        gfp_t gfp;
 
        /* Assert that the object is not currently in any GPU domain. As it
@@ -2246,8 +2246,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
                         */
                        i915_gem_shrink_all(dev_priv);
                        page = shmem_read_mapping_page(mapping, i);
-                       if (IS_ERR(page))
+                       if (IS_ERR(page)) {
+                               ret = PTR_ERR(page);
                                goto err_pages;
+                       }
                }
 #ifdef CONFIG_SWIOTLB
                if (swiotlb_nr_tbl()) {
@@ -2276,6 +2278,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
                sg_mark_end(sg);
        obj->pages = st;
 
+       ret = i915_gem_gtt_prepare_object(obj);
+       if (ret)
+               goto err_pages;
+
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_do_bit_17_swizzle(obj);
 
@@ -2300,10 +2306,10 @@ err_pages:
         * space and so want to translate the error from shmemfs back to our
         * usual understanding of ENOMEM.
         */
-       if (PTR_ERR(page) == -ENOSPC)
-               return -ENOMEM;
-       else
-               return PTR_ERR(page);
+       if (ret == -ENOSPC)
+               ret = -ENOMEM;
+
+       return ret;
 }
 
 /* Ensure that the associated pages are gathered from the backing storage
@@ -2542,6 +2548,7 @@ int __i915_add_request(struct intel_engine_cs *ring,
        }
 
        request->emitted_jiffies = jiffies;
+       ring->last_submitted_seqno = request->seqno;
        list_add_tail(&request->list, &ring->request_list);
        request->file_priv = NULL;
 
@@ -3247,10 +3254,8 @@ int i915_vma_unbind(struct i915_vma *vma)
 
        /* Since the unbound list is global, only move to that list if
         * no more VMAs exist. */
-       if (list_empty(&obj->vma_list)) {
-               i915_gem_gtt_finish_object(obj);
+       if (list_empty(&obj->vma_list))
                list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
-       }
 
        /* And finally now the object is completely decoupled from this vma,
         * we can drop its hold on the backing storage and allow it to be
@@ -3768,22 +3773,16 @@ search_free:
                goto err_remove_node;
        }
 
-       ret = i915_gem_gtt_prepare_object(obj);
-       if (ret)
-               goto err_remove_node;
-
        trace_i915_vma_bind(vma, flags);
        ret = i915_vma_bind(vma, obj->cache_level, flags);
        if (ret)
-               goto err_finish_gtt;
+               goto err_remove_node;
 
        list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
        list_add_tail(&vma->mm_list, &vm->inactive_list);
 
        return vma;
 
-err_finish_gtt:
-       i915_gem_gtt_finish_object(obj);
 err_remove_node:
        drm_mm_remove_node(&vma->node);
 err_free_vma:
index 8867818b140173fc3c107b299a7b553a6287f8f9..48afa777e94aa849e13890be64b3d4303283eee1 100644 (file)
@@ -135,8 +135,7 @@ static int get_context_size(struct drm_device *dev)
 
 void i915_gem_context_free(struct kref *ctx_ref)
 {
-       struct intel_context *ctx = container_of(ctx_ref,
-                                                typeof(*ctx), ref);
+       struct intel_context *ctx = container_of(ctx_ref, typeof(*ctx), ref);
 
        trace_i915_context_free(ctx);
 
@@ -157,9 +156,7 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
        struct drm_i915_gem_object *obj;
        int ret;
 
-       obj = i915_gem_object_create_stolen(dev, size);
-       if (obj == NULL)
-               obj = i915_gem_alloc_object(dev, size);
+       obj = i915_gem_alloc_object(dev, size);
        if (obj == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -197,6 +194,7 @@ __create_hw_context(struct drm_device *dev,
 
        kref_init(&ctx->ref);
        list_add_tail(&ctx->link, &dev_priv->context_list);
+       ctx->i915 = dev_priv;
 
        if (dev_priv->hw_context_size) {
                struct drm_i915_gem_object *obj =
index 7998da27c500744c78fd0897193b19f778244ca7..e9c2bfd85b5268425ce9465ee2d23d99ee92c534 100644 (file)
@@ -256,7 +256,6 @@ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
                return PTR_ERR(sg);
 
        obj->pages = sg;
-       obj->has_dma_mapping = true;
        return 0;
 }
 
@@ -264,7 +263,6 @@ static void i915_gem_object_put_pages_dmabuf(struct drm_i915_gem_object *obj)
 {
        dma_buf_unmap_attachment(obj->base.import_attach,
                                 obj->pages, DMA_BIDIRECTIONAL);
-       obj->has_dma_mapping = false;
 }
 
 static const struct drm_i915_gem_object_ops i915_gem_object_dmabuf_ops = {
index 9daa2883ac186f73c64baa40ba61aadfd0a94c9a..31e8269e6e3dab33d809f693f7cc6ce8cf318975 100644 (file)
@@ -1723,9 +1723,6 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
 
 int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
 {
-       if (obj->has_dma_mapping)
-               return 0;
-
        if (!dma_map_sg(&obj->base.dev->pdev->dev,
                        obj->pages->sgl, obj->pages->nents,
                        PCI_DMA_BIDIRECTIONAL))
@@ -1926,6 +1923,17 @@ static int ggtt_bind_vma(struct i915_vma *vma,
                vma->vm->insert_entries(vma->vm, pages,
                                        vma->node.start,
                                        cache_level, pte_flags);
+
+               /* Note the inconsistency here is due to absence of the
+                * aliasing ppgtt on gen4 and earlier. Though we always
+                * request PIN_USER for execbuffer (translated to LOCAL_BIND),
+                * without the appgtt, we cannot honour that request and so
+                * must substitute it with a global binding. Since we do this
+                * behind the upper layers back, we need to explicitly set
+                * the bound flag ourselves.
+                */
+               vma->bound |= GLOBAL_BIND;
+
        }
 
        if (dev_priv->mm.aliasing_ppgtt && flags & LOCAL_BIND) {
@@ -1972,10 +1980,8 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
 
        interruptible = do_idling(dev_priv);
 
-       if (!obj->has_dma_mapping)
-               dma_unmap_sg(&dev->pdev->dev,
-                            obj->pages->sgl, obj->pages->nents,
-                            PCI_DMA_BIDIRECTIONAL);
+       dma_unmap_sg(&dev->pdev->dev, obj->pages->sgl, obj->pages->nents,
+                    PCI_DMA_BIDIRECTIONAL);
 
        undo_idling(dev_priv, interruptible);
 }
@@ -2546,6 +2552,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct i915_address_space *vm;
+       struct i915_vma *vma;
+       bool flush;
 
        i915_check_and_clear_faults(dev);
 
@@ -2555,16 +2563,23 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
                                       dev_priv->gtt.base.total,
                                       true);
 
+       /* Cache flush objects bound into GGTT and rebind them. */
+       vm = &dev_priv->gtt.base;
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               struct i915_vma *vma = i915_gem_obj_to_vma(obj,
-                                                          &dev_priv->gtt.base);
-               if (!vma)
-                       continue;
+               flush = false;
+               list_for_each_entry(vma, &obj->vma_list, vma_link) {
+                       if (vma->vm != vm)
+                               continue;
 
-               i915_gem_clflush_object(obj, obj->pin_display);
-               WARN_ON(i915_vma_bind(vma, obj->cache_level, PIN_UPDATE));
-       }
+                       WARN_ON(i915_vma_bind(vma, obj->cache_level,
+                                             PIN_UPDATE));
 
+                       flush = true;
+               }
+
+               if (flush)
+                       i915_gem_clflush_object(obj, obj->pin_display);
+       }
 
        if (INTEL_INFO(dev)->gen >= 8) {
                if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev))
index 348ed5abcdbf6d9745193254952da8f85a8c6909..8b5b784c62fea276fc9bc947a85734f75f81a9eb 100644 (file)
@@ -416,7 +416,6 @@ _i915_gem_object_create_stolen(struct drm_device *dev,
        if (obj->pages == NULL)
                goto cleanup;
 
-       obj->has_dma_mapping = true;
        i915_gem_object_pin_pages(obj);
        obj->stolen = stolen;
 
index 633bd1fcab6925881048e7310f9aa40e4f9db868..d19c9db5e18c9d57057ad78ffdbdfa1a65b861b4 100644 (file)
@@ -464,7 +464,10 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
        }
 
        /* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */
-       args->phys_swizzle_mode = args->swizzle_mode;
+       if (dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES)
+               args->phys_swizzle_mode = I915_BIT_6_SWIZZLE_UNKNOWN;
+       else
+               args->phys_swizzle_mode = args->swizzle_mode;
        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
                args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
index 1f4e5a32a16e568cae0cc340c39482d13af7ef41..8fd431bcdfd3a33ffb6afda7a1584b44e33d8296 100644 (file)
@@ -545,6 +545,26 @@ err:
        return ret;
 }
 
+static int
+__i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj,
+                            struct page **pvec, int num_pages)
+{
+       int ret;
+
+       ret = st_set_pages(&obj->pages, pvec, num_pages);
+       if (ret)
+               return ret;
+
+       ret = i915_gem_gtt_prepare_object(obj);
+       if (ret) {
+               sg_free_table(obj->pages);
+               kfree(obj->pages);
+               obj->pages = NULL;
+       }
+
+       return ret;
+}
+
 static void
 __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
 {
@@ -584,9 +604,12 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
        if (obj->userptr.work != &work->work) {
                ret = 0;
        } else if (pinned == num_pages) {
-               ret = st_set_pages(&obj->pages, pvec, num_pages);
+               ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
                if (ret == 0) {
                        list_add_tail(&obj->global_list, &to_i915(dev)->mm.unbound_list);
+                       obj->get_page.sg = obj->pages->sgl;
+                       obj->get_page.last = 0;
+
                        pinned = 0;
                }
        }
@@ -693,7 +716,7 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
                        }
                }
        } else {
-               ret = st_set_pages(&obj->pages, pvec, num_pages);
+               ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
                if (ret == 0) {
                        obj->userptr.work = NULL;
                        pinned = 0;
@@ -715,6 +738,8 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj)
        if (obj->madv != I915_MADV_WILLNEED)
                obj->dirty = 0;
 
+       i915_gem_gtt_finish_object(obj);
+
        for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
                struct page *page = sg_page_iter_page(&sg_iter);
 
index 176de6322e4d0039482422bc1210ff89a1af769b..23aa04cded6b013d6e78c046926cc63d03dae628 100644 (file)
@@ -204,7 +204,7 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        drm_ioctl_compat_t *fn = NULL;
        int ret;
 
-       if (nr < DRM_COMMAND_BASE)
+       if (nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END)
                return drm_compat_ioctl(filp, cmd, arg);
 
        if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(i915_compat_ioctls))
index e6bb72dca3ffb15ae732aac0291dc13806eaba92..984e2fe6688c4c2cabd8829fe2e5cad97e88770e 100644 (file)
@@ -2706,18 +2706,11 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-static struct drm_i915_gem_request *
-ring_last_request(struct intel_engine_cs *ring)
-{
-       return list_entry(ring->request_list.prev,
-                         struct drm_i915_gem_request, list);
-}
-
 static bool
-ring_idle(struct intel_engine_cs *ring)
+ring_idle(struct intel_engine_cs *ring, u32 seqno)
 {
        return (list_empty(&ring->request_list) ||
-               i915_gem_request_completed(ring_last_request(ring), false));
+               i915_seqno_passed(seqno, ring->last_submitted_seqno));
 }
 
 static bool
@@ -2939,7 +2932,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                acthd = intel_ring_get_active_head(ring);
 
                if (ring->hangcheck.seqno == seqno) {
-                       if (ring_idle(ring)) {
+                       if (ring_idle(ring, seqno)) {
                                ring->hangcheck.action = HANGCHECK_IDLE;
 
                                if (waitqueue_active(&ring->irq_queue)) {
index 497cba5deb1e9db162a6a59c0993ca4c4712e649..849a2590e010ca1d10de85fea06cbb41211ad2d8 100644 (file)
@@ -727,7 +727,7 @@ DECLARE_EVENT_CLASS(i915_context,
        TP_fast_assign(
                        __entry->ctx = ctx;
                        __entry->vm = ctx->ppgtt ? &ctx->ppgtt->base : NULL;
-                       __entry->dev = ctx->file_priv->dev_priv->dev->primary->index;
+                       __entry->dev = ctx->i915->dev->primary->index;
        ),
 
        TP_printk("dev=%u, ctx=%p, ctx_vm=%p",
index 7ed8033aae6097af69d90e83bb6c97f7dc6f7225..8e35e0d013df556d8ac04fc27f9ba2bd7354fae3 100644 (file)
@@ -129,8 +129,9 @@ int intel_atomic_commit(struct drm_device *dev,
                        struct drm_atomic_state *state,
                        bool async)
 {
-       int ret;
-       int i;
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       int ret, i;
 
        if (async) {
                DRM_DEBUG_KMS("i915 does not yet support async commit\n");
@@ -142,48 +143,18 @@ int intel_atomic_commit(struct drm_device *dev,
                return ret;
 
        /* Point of no return */
-
-       /*
-        * FIXME:  The proper sequence here will eventually be:
-        *
-        * drm_atomic_helper_swap_state(dev, state)
-        * drm_atomic_helper_commit_modeset_disables(dev, state);
-        * drm_atomic_helper_commit_planes(dev, state);
-        * drm_atomic_helper_commit_modeset_enables(dev, state);
-        * drm_atomic_helper_wait_for_vblanks(dev, state);
-        * drm_atomic_helper_cleanup_planes(dev, state);
-        * drm_atomic_state_free(state);
-        *
-        * once we have full atomic modeset.  For now, just manually update
-        * plane states to avoid clobbering good states with dummy states
-        * while nuclear pageflipping.
-        */
-       for (i = 0; i < dev->mode_config.num_total_plane; i++) {
-               struct drm_plane *plane = state->planes[i];
-
-               if (!plane)
-                       continue;
-
-               plane->state->state = state;
-               swap(state->plane_states[i], plane->state);
-               plane->state->state = NULL;
-       }
+       drm_atomic_helper_swap_state(dev, state);
 
        /* swap crtc_scaler_state */
-       for (i = 0; i < dev->mode_config.num_crtc; i++) {
-               struct drm_crtc *crtc = state->crtcs[i];
-               if (!crtc) {
-                       continue;
-               }
-
-               to_intel_crtc(crtc)->config->scaler_state =
-                       to_intel_crtc_state(state->crtc_states[i])->scaler_state;
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state);
 
                if (INTEL_INFO(dev)->gen >= 9)
                        skl_detach_scalers(to_intel_crtc(crtc));
+
+               drm_atomic_helper_commit_planes_on_crtc(crtc_state);
        }
 
-       drm_atomic_helper_commit_planes(dev, state);
        drm_atomic_helper_wait_for_vblanks(dev, state);
        drm_atomic_helper_cleanup_planes(dev, state);
        drm_atomic_state_free(state);
index 1b61f98103870171e75338595b32e5dd473523e0..87476ff181ddbef0967d948c37119cfcbd758315 100644 (file)
@@ -4854,6 +4854,9 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
        struct intel_plane *intel_plane;
        int pipe = intel_crtc->pipe;
 
+       if (!intel_crtc->active)
+               return;
+
        intel_crtc_wait_for_pending_flips(crtc);
 
        intel_pre_disable_primary(crtc);
@@ -6312,9 +6315,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
        struct drm_connector *connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* crtc should still be enabled when we disable it. */
-       WARN_ON(!crtc->state->enable);
-
        intel_crtc_disable_planes(crtc);
        dev_priv->display.crtc_disable(crtc);
        dev_priv->display.off(crtc);
@@ -7887,7 +7887,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
        int pipe = pipe_config->cpu_transcoder;
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
        intel_clock_t clock;
-       u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2;
+       u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3;
        int refclk = 100000;
 
        mutex_lock(&dev_priv->sb_lock);
@@ -7895,10 +7895,13 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
        pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port));
        pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port));
        pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port));
+       pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
        mutex_unlock(&dev_priv->sb_lock);
 
        clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0;
-       clock.m2 = ((pll_dw0 & 0xff) << 22) | (pll_dw2 & 0x3fffff);
+       clock.m2 = (pll_dw0 & 0xff) << 22;
+       if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN)
+               clock.m2 |= pll_dw2 & 0x3fffff;
        clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf;
        clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7;
        clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f;
@@ -11823,7 +11826,9 @@ encoder_retry:
                goto encoder_retry;
        }
 
-       pipe_config->dither = pipe_config->pipe_bpp != base_bpp;
+       /* Dithering seems to not pass-through bits correctly when it should, so
+        * only enable it on 6bpc panels. */
+       pipe_config->dither = pipe_config->pipe_bpp == 6*3;
        DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
                      base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
 
@@ -12585,7 +12590,8 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc,
                        continue;
 
                if (!crtc_state->enable) {
-                       intel_crtc_disable(crtc);
+                       if (crtc->state->enable)
+                               intel_crtc_disable(crtc);
                } else if (crtc->state->enable) {
                        intel_crtc_disable_planes(crtc);
                        dev_priv->display.crtc_disable(crtc);
@@ -12620,17 +12626,17 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc,
 
        modeset_update_crtc_power_domains(state);
 
-       drm_atomic_helper_commit_planes(dev, state);
-
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
-               if (!needs_modeset(crtc->state) || !crtc->state->enable)
+               if (!needs_modeset(crtc->state) || !crtc->state->enable) {
+                       drm_atomic_helper_commit_planes_on_crtc(crtc_state);
                        continue;
+               }
 
                update_scanline_offset(to_intel_crtc(crtc));
 
                dev_priv->display.crtc_enable(crtc);
-               intel_crtc_enable_planes(crtc);
+               drm_atomic_helper_commit_planes_on_crtc(crtc_state);
        }
 
        /* FIXME: add subpixel order */
@@ -12887,20 +12893,11 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        return 0;
 }
 
-static bool primary_plane_visible(struct drm_crtc *crtc)
-{
-       struct intel_plane_state *plane_state =
-               to_intel_plane_state(crtc->primary->state);
-
-       return plane_state->visible;
-}
-
 static int intel_crtc_set_config(struct drm_mode_set *set)
 {
        struct drm_device *dev;
        struct drm_atomic_state *state = NULL;
        struct intel_crtc_state *pipe_config;
-       bool primary_plane_was_visible;
        int ret;
 
        BUG_ON(!set);
@@ -12939,38 +12936,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 
        intel_update_pipe_size(to_intel_crtc(set->crtc));
 
-       primary_plane_was_visible = primary_plane_visible(set->crtc);
-
        ret = intel_set_mode_with_config(set->crtc, pipe_config, true);
 
-       if (ret == 0 &&
-           pipe_config->base.enable &&
-           pipe_config->base.planes_changed &&
-           !needs_modeset(&pipe_config->base)) {
-               struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
-
-               /*
-                * We need to make sure the primary plane is re-enabled if it
-                * has previously been turned off.
-                */
-               if (ret == 0 && !primary_plane_was_visible &&
-                   primary_plane_visible(set->crtc)) {
-                       WARN_ON(!intel_crtc->active);
-                       intel_post_enable_primary(set->crtc);
-               }
-
-               /*
-                * In the fastboot case this may be our only check of the
-                * state after boot.  It would be better to only do it on
-                * the first update, but we don't have a nice way of doing that
-                * (and really, set_config isn't used much for high freq page
-                * flipping, so increasing its cost here shouldn't be a big
-                * deal).
-                */
-               if (i915.fastboot && ret == 0)
-                       intel_modeset_check_state(set->crtc->dev);
-       }
-
        if (ret) {
                DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
                              set->crtc->base.id, ret);
@@ -13270,7 +13237,7 @@ intel_check_primary_plane(struct drm_plane *plane,
        if (ret)
                return ret;
 
-       if (intel_crtc->active) {
+       if (crtc_state ? crtc_state->base.active : intel_crtc->active) {
                struct intel_plane_state *old_state =
                        to_intel_plane_state(plane->state);
 
@@ -13301,6 +13268,9 @@ intel_check_primary_plane(struct drm_plane *plane,
                         */
                        if (IS_BROADWELL(dev))
                                intel_crtc->atomic.wait_vblank = true;
+
+                       if (crtc_state)
+                               intel_crtc->atomic.post_enable_primary = true;
                }
 
                /*
@@ -13313,6 +13283,10 @@ intel_check_primary_plane(struct drm_plane *plane,
                if (!state->visible || !fb)
                        intel_crtc->atomic.disable_ips = true;
 
+               if (!state->visible && old_state->visible &&
+                   crtc_state && !needs_modeset(&crtc_state->base))
+                       intel_crtc->atomic.pre_disable_primary = true;
+
                intel_crtc->atomic.fb_bits |=
                        INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
 
@@ -15030,6 +15004,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                struct intel_plane_state *plane_state;
 
                memset(crtc->config, 0, sizeof(*crtc->config));
+               crtc->config->base.crtc = &crtc->base;
 
                crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
 
index 6e8faa25379240cab60f57631adf42612f28df33..1df0e1fe235f112830a0e82a1004b0e949613c78 100644 (file)
@@ -93,9 +93,6 @@ static const struct dp_link_dpll chv_dpll[] = {
 
 static const int skl_rates[] = { 162000, 216000, 270000,
                                  324000, 432000, 540000 };
-static const int chv_rates[] = { 162000, 202500, 210000, 216000,
-                                243000, 270000, 324000, 405000,
-                                420000, 432000, 540000 };
 static const int default_rates[] = { 162000, 270000, 540000 };
 
 /**
@@ -1169,24 +1166,31 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
        return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
 }
 
+static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
+{
+       /* WaDisableHBR2:skl */
+       if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
+               return false;
+
+       if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
+           (INTEL_INFO(dev)->gen >= 9))
+               return true;
+       else
+               return false;
+}
+
 static int
 intel_dp_source_rates(struct drm_device *dev, const int **source_rates)
 {
        if (IS_SKYLAKE(dev)) {
                *source_rates = skl_rates;
                return ARRAY_SIZE(skl_rates);
-       } else if (IS_CHERRYVIEW(dev)) {
-               *source_rates = chv_rates;
-               return ARRAY_SIZE(chv_rates);
        }
 
        *source_rates = default_rates;
 
-       if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0)
-               /* WaDisableHBR2:skl */
-               return (DP_LINK_BW_2_7 >> 3) + 1;
-       else if (INTEL_INFO(dev)->gen >= 8 ||
-           (IS_HASWELL(dev) && !IS_HSW_ULX(dev)))
+       /* This depends on the fact that 5.4 is last value in the array */
+       if (intel_dp_source_supports_hbr2(dev))
                return (DP_LINK_BW_5_4 >> 3) + 1;
        else
                return (DP_LINK_BW_2_7 >> 3) + 1;
@@ -3941,10 +3945,15 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
                }
        }
 
-       /* Training Pattern 3 support, both source and sink */
+       /* Training Pattern 3 support, Intel platforms that support HBR2 alone
+        * have support for TP3 hence that check is used along with dpcd check
+        * to ensure TP3 can be enabled.
+        * SKL < B0: due it's WaDisableHBR2 is the only exception where TP3 is
+        * supported but still not enabled.
+        */
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
            intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED &&
-           (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)) {
+           intel_dp_source_supports_hbr2(dev)) {
                intel_dp->use_tps3 = true;
                DRM_DEBUG_KMS("Displayport TPS3 supported\n");
        } else
index 6e4cc5334f47d7105b60c0bec72fccfb4875ddac..600afdbef8c9a434f51d527c5d85e202c36bae2b 100644 (file)
@@ -357,6 +357,16 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
+static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
+                                                        struct drm_connector_state *state)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_dp *intel_dp = intel_connector->mst_port;
+       struct intel_crtc *crtc = to_intel_crtc(state->crtc);
+
+       return &intel_dp->mst_encoders[crtc->pipe]->base.base;
+}
+
 static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -367,6 +377,7 @@ static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connecto
 static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
        .get_modes = intel_dp_mst_get_modes,
        .mode_valid = intel_dp_mst_mode_valid,
+       .atomic_best_encoder = intel_mst_atomic_best_encoder,
        .best_encoder = intel_mst_best_encoder,
 };
 
index 9b74ffae5f5a7bab8ef545525d361c29fd4c3bf6..7f2161a1ff5d4d40c7b6dca346c20518b084bf6b 100644 (file)
@@ -1012,6 +1012,8 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
                ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
                if (ret)
                        goto unpin_ctx_obj;
+
+               ctx_obj->dirty = true;
        }
 
        return ret;
index e539314ae87e0280b3d1195c380c4e3764e7c330..4be66f60504d13661f07886cb891fd9417da754f 100644 (file)
@@ -275,6 +275,13 @@ struct  intel_engine_cs {
         * Do we have some not yet emitted requests outstanding?
         */
        struct drm_i915_gem_request *outstanding_lazy_request;
+       /**
+        * Seqno of request most recently submitted to request_list.
+        * Used exclusively by hang checker to avoid grabbing lock while
+        * inspecting request list.
+        */
+       u32 last_submitted_seqno;
+
        bool gpu_caches_dirty;
 
        wait_queue_head_t irq_queue;
index a6d8a3ee7750adecb552415c8ffab06d599f46ff..260389acfb7752d01ce0ebd59597f06a671b2ea1 100644 (file)
@@ -1274,10 +1274,12 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_reg_read *reg = data;
        struct register_whitelist const *entry = whitelist;
+       unsigned size;
+       u64 offset;
        int i, ret = 0;
 
        for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
-               if (entry->offset == reg->offset &&
+               if (entry->offset == (reg->offset & -entry->size) &&
                    (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask))
                        break;
        }
@@ -1285,23 +1287,33 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        if (i == ARRAY_SIZE(whitelist))
                return -EINVAL;
 
+       /* We use the low bits to encode extra flags as the register should
+        * be naturally aligned (and those that are not so aligned merely
+        * limit the available flags for that register).
+        */
+       offset = entry->offset;
+       size = entry->size;
+       size |= reg->offset ^ offset;
+
        intel_runtime_pm_get(dev_priv);
 
-       switch (entry->size) {
+       switch (size) {
+       case 8 | 1:
+               reg->val = I915_READ64_2x32(offset, offset+4);
+               break;
        case 8:
-               reg->val = I915_READ64(reg->offset);
+               reg->val = I915_READ64(offset);
                break;
        case 4:
-               reg->val = I915_READ(reg->offset);
+               reg->val = I915_READ(offset);
                break;
        case 2:
-               reg->val = I915_READ16(reg->offset);
+               reg->val = I915_READ16(offset);
                break;
        case 1:
-               reg->val = I915_READ8(reg->offset);
+               reg->val = I915_READ8(offset);
                break;
        default:
-               MISSING_CASE(entry->size);
                ret = -EINVAL;
                goto out;
        }
index 214eceefc981e4018b9aeb262ad2ebbc4b4abfa0..e671ad3694166041ce76c4eaa57539897eba81d1 100644 (file)
@@ -301,7 +301,7 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
 
        switch (tve->mode) {
        case TVE_MODE_VGA:
-               imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_YUV8_1X24,
+               imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_GBR888_1X24,
                                            tve->hsync_pin, tve->vsync_pin);
                break;
        case TVE_MODE_TVOUT:
index 74a9ce40ddc457f476611478d87f14ec2f67d8fd..b4deb9cf9d71613fa49562c4619cf8ffec5a33f3 100644 (file)
@@ -21,6 +21,7 @@
 #include <drm/drm_panel.h>
 #include <linux/videodev2.h>
 #include <video/of_display_timing.h>
+#include <linux/of_graph.h>
 
 #include "imx-drm.h"
 
@@ -208,7 +209,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 {
        struct drm_device *drm = data;
        struct device_node *np = dev->of_node;
-       struct device_node *panel_node;
+       struct device_node *port;
        const u8 *edidp;
        struct imx_parallel_display *imxpd;
        int ret;
@@ -234,11 +235,19 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
                        imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
        }
 
-       panel_node = of_parse_phandle(np, "fsl,panel", 0);
-       if (panel_node) {
-               imxpd->panel = of_drm_find_panel(panel_node);
-               if (!imxpd->panel)
-                       return -EPROBE_DEFER;
+       /* port@1 is the output port */
+       port = of_graph_get_port_by_id(np, 1);
+       if (port) {
+               struct device_node *endpoint, *remote;
+
+               endpoint = of_get_child_by_name(port, "endpoint");
+               if (endpoint) {
+                       remote = of_graph_get_remote_port_parent(endpoint);
+                       if (remote)
+                               imxpd->panel = of_drm_find_panel(remote);
+                       if (!imxpd->panel)
+                               return -EPROBE_DEFER;
+               }
        }
 
        imxpd->dev = dev;
index 0d1dbb73793355043d514f2c4239e16386671e00..247a424445f75bb4d27573e0d9ac208262a6ac97 100644 (file)
@@ -220,13 +220,15 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
        uint32_t op_mode = 0;
        uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
        uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
-       enum mdp4_frame_format frame_type = mdp4_get_frame_format(fb);
+       enum mdp4_frame_format frame_type;
 
        if (!(crtc && fb)) {
                DBG("%s: disabled!", mdp4_plane->name);
                return 0;
        }
 
+       frame_type = mdp4_get_frame_format(fb);
+
        /* src values are in Q16 fixed point, convert to integer: */
        src_x = src_x >> 16;
        src_y = src_y >> 16;
index 206f758f7d64849af986e6c70589bf96d7b0cb7b..e253db5de5aa5955a2841f9ff8cdc63e5b519fac 100644 (file)
@@ -76,7 +76,20 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st
 
 static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
 {
+       int i;
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       int nplanes = mdp5_kms->dev->mode_config.num_total_plane;
+
+       for (i = 0; i < nplanes; i++) {
+               struct drm_plane *plane = state->planes[i];
+               struct drm_plane_state *plane_state = state->plane_states[i];
+
+               if (!plane)
+                       continue;
+
+               mdp5_plane_complete_commit(plane, plane_state);
+       }
+
        mdp5_disable(mdp5_kms);
 }
 
index e0eb24587c84d7887a69c47c0428ad3f0d4f1396..e79ac09b72168c4f2af8be041d541736a81223fc 100644 (file)
@@ -227,6 +227,8 @@ void mdp5_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
 uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
 void mdp5_plane_complete_flip(struct drm_plane *plane);
+void mdp5_plane_complete_commit(struct drm_plane *plane,
+       struct drm_plane_state *state);
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
                enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset);
index 57b8f56ae9d06fb458266181a8344858e381e6b5..22275568ab8be3a500c82f138b4c4bb04a088de4 100644 (file)
@@ -31,8 +31,6 @@ struct mdp5_plane {
 
        uint32_t nformats;
        uint32_t formats[32];
-
-       bool enabled;
 };
 #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
 
@@ -56,22 +54,6 @@ static bool plane_enabled(struct drm_plane_state *state)
        return state->fb && state->crtc;
 }
 
-static int mdp5_plane_disable(struct drm_plane *plane)
-{
-       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-       struct mdp5_kms *mdp5_kms = get_kms(plane);
-       enum mdp5_pipe pipe = mdp5_plane->pipe;
-
-       DBG("%s: disable", mdp5_plane->name);
-
-       if (mdp5_kms) {
-               /* Release the memory we requested earlier from the SMP: */
-               mdp5_smp_release(mdp5_kms->smp, pipe);
-       }
-
-       return 0;
-}
-
 static void mdp5_plane_destroy(struct drm_plane *plane)
 {
        struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
@@ -224,7 +206,6 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane,
 
        if (!plane_enabled(state)) {
                to_mdp5_plane_state(state)->pending = true;
-               mdp5_plane_disable(plane);
        } else if (to_mdp5_plane_state(state)->mode_changed) {
                int ret;
                to_mdp5_plane_state(state)->pending = true;
@@ -602,6 +583,20 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
        return mdp5_plane->flush_mask;
 }
 
+/* called after vsync in thread context */
+void mdp5_plane_complete_commit(struct drm_plane *plane,
+       struct drm_plane_state *state)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+
+       if (!plane_enabled(plane->state)) {
+               DBG("%s: free SMP", mdp5_plane->name);
+               mdp5_smp_release(mdp5_kms->smp, pipe);
+       }
+}
+
 /* initialize plane */
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
                enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset)
index 16702aecf0df714e211b8d7900fc06299e0e92f8..64a27d86f2f521444469b29e70ca9861f17d09db 100644 (file)
  * and CANNOT be re-allocated (eg: MMB0 and MMB1 both tied to RGB0).
  *
  * For each block that can be dynamically allocated, it can be either
- * free, or pending/in-use by a client. The updates happen in three steps:
+ *     free:
+ *     The block is free.
+ *
+ *     pending:
+ *     The block is allocated to some client and not free.
+ *
+ *     configured:
+ *     The block is allocated to some client, and assigned to that
+ *     client in MDP5_MDP_SMP_ALLOC registers.
+ *
+ *     inuse:
+ *     The block is being actively used by a client.
+ *
+ * The updates happen in the following steps:
  *
  *  1) mdp5_smp_request():
  *     When plane scanout is setup, calculate required number of
- *     blocks needed per client, and request.  Blocks not inuse or
- *     pending by any other client are added to client's pending
- *     set.
+ *     blocks needed per client, and request. Blocks neither inuse nor
+ *     configured nor pending by any other client are added to client's
+ *     pending set.
+ *     For shrinking, blocks in pending but not in configured can be freed
+ *     directly, but those already in configured will be freed later by
+ *     mdp5_smp_commit.
  *
  *  2) mdp5_smp_configure():
  *     As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers
  *     are configured for the union(pending, inuse)
+ *     Current pending is copied to configured.
+ *     It is assumed that mdp5_smp_request and mdp5_smp_configure not run
+ *     concurrently for the same pipe.
  *
  *  3) mdp5_smp_commit():
- *     After next vblank, copy pending -> inuse.  Optionally update
+ *     After next vblank, copy configured -> inuse.  Optionally update
  *     MDP5_SMP_ALLOC registers if there are newly unused blocks
  *
+ *  4) mdp5_smp_release():
+ *     Must be called after the pipe is disabled and no longer uses any SMB
+ *
  * On the next vblank after changes have been committed to hw, the
  * client's pending blocks become it's in-use blocks (and no-longer
  * in-use blocks become available to other clients).
@@ -77,6 +99,9 @@ struct mdp5_smp {
        struct mdp5_client_smp_state client_state[MAX_CLIENTS];
 };
 
+static void update_smp_state(struct mdp5_smp *smp,
+               u32 cid, mdp5_smp_state_t *assigned);
+
 static inline
 struct mdp5_kms *get_kms(struct mdp5_smp *smp)
 {
@@ -149,7 +174,12 @@ static int smp_request_block(struct mdp5_smp *smp,
                for (i = cur_nblks; i > nblks; i--) {
                        int blk = find_first_bit(ps->pending, cnt);
                        clear_bit(blk, ps->pending);
-                       /* don't clear in global smp_state until _commit() */
+
+                       /* clear in global smp_state if not in configured
+                        * otherwise until _commit()
+                        */
+                       if (!test_bit(blk, ps->configured))
+                               clear_bit(blk, smp->state);
                }
        }
 
@@ -223,10 +253,33 @@ int mdp5_smp_request(struct mdp5_smp *smp, enum mdp5_pipe pipe, u32 fmt, u32 wid
 /* Release SMP blocks for all clients of the pipe */
 void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 {
-       int i, nblks;
+       int i;
+       unsigned long flags;
+       int cnt = smp->blk_cnt;
+
+       for (i = 0; i < pipe2nclients(pipe); i++) {
+               mdp5_smp_state_t assigned;
+               u32 cid = pipe2client(pipe, i);
+               struct mdp5_client_smp_state *ps = &smp->client_state[cid];
+
+               spin_lock_irqsave(&smp->state_lock, flags);
+
+               /* clear hw assignment */
+               bitmap_or(assigned, ps->inuse, ps->configured, cnt);
+               update_smp_state(smp, CID_UNUSED, &assigned);
+
+               /* free to global pool */
+               bitmap_andnot(smp->state, smp->state, ps->pending, cnt);
+               bitmap_andnot(smp->state, smp->state, assigned, cnt);
+
+               /* clear client's infor */
+               bitmap_zero(ps->pending, cnt);
+               bitmap_zero(ps->configured, cnt);
+               bitmap_zero(ps->inuse, cnt);
+
+               spin_unlock_irqrestore(&smp->state_lock, flags);
+       }
 
-       for (i = 0, nblks = 0; i < pipe2nclients(pipe); i++)
-               smp_request_block(smp, pipe2client(pipe, i), 0);
        set_fifo_thresholds(smp, pipe, 0);
 }
 
@@ -274,12 +327,20 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
                u32 cid = pipe2client(pipe, i);
                struct mdp5_client_smp_state *ps = &smp->client_state[cid];
 
-               bitmap_or(assigned, ps->inuse, ps->pending, cnt);
+               /*
+                * if vblank has not happened since last smp_configure
+                * skip the configure for now
+                */
+               if (!bitmap_equal(ps->inuse, ps->configured, cnt))
+                       continue;
+
+               bitmap_copy(ps->configured, ps->pending, cnt);
+               bitmap_or(assigned, ps->inuse, ps->configured, cnt);
                update_smp_state(smp, cid, &assigned);
        }
 }
 
-/* step #3: after vblank, copy pending -> inuse: */
+/* step #3: after vblank, copy configured -> inuse: */
 void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
 {
        int cnt = smp->blk_cnt;
@@ -295,7 +356,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
                 * using, which can be released and made available to other
                 * clients:
                 */
-               if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) {
+               if (bitmap_andnot(released, ps->inuse, ps->configured, cnt)) {
                        unsigned long flags;
 
                        spin_lock_irqsave(&smp->state_lock, flags);
@@ -306,7 +367,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
                        update_smp_state(smp, CID_UNUSED, &released);
                }
 
-               bitmap_copy(ps->inuse, ps->pending, cnt);
+               bitmap_copy(ps->inuse, ps->configured, cnt);
        }
 }
 
index e47179f635852a2f6ee546378200ce0a54a64499..5b6c2363f59280266a58a407a17c91b00eb8d9a3 100644 (file)
@@ -23,6 +23,7 @@
 
 struct mdp5_client_smp_state {
        mdp5_smp_state_t inuse;
+       mdp5_smp_state_t configured;
        mdp5_smp_state_t pending;
 };
 
index 1b22d8bfe142097f507435613b5bbd25311d4700..1ceb4f22dd8997a7b4e772d82e646abb1a87c7ff 100644 (file)
@@ -283,12 +283,8 @@ int msm_atomic_commit(struct drm_device *dev,
 
        timeout = ktime_add_ms(ktime_get(), 1000);
 
-       ret = msm_wait_fence_interruptable(dev, c->fence, &timeout);
-       if (ret) {
-               WARN_ON(ret);  // TODO unswap state back?  or??
-               commit_destroy(c);
-               return ret;
-       }
+       /* uninterruptible wait */
+       msm_wait_fence(dev, c->fence, &timeout, false);
 
        complete_commit(c);
 
index b7ef56ed8d1cf5280f942d83d2305672b414e0d8..d3467b115e0482a6eca2ebd6a5810e31f69220fa 100644 (file)
@@ -637,8 +637,8 @@ static void msm_debugfs_cleanup(struct drm_minor *minor)
  * Fences:
  */
 
-int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
-               ktime_t *timeout)
+int msm_wait_fence(struct drm_device *dev, uint32_t fence,
+               ktime_t *timeout , bool interruptible)
 {
        struct msm_drm_private *priv = dev->dev_private;
        int ret;
@@ -667,7 +667,12 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                        remaining_jiffies = timespec_to_jiffies(&ts);
                }
 
-               ret = wait_event_interruptible_timeout(priv->fence_event,
+               if (interruptible)
+                       ret = wait_event_interruptible_timeout(priv->fence_event,
+                               fence_completed(dev, fence),
+                               remaining_jiffies);
+               else
+                       ret = wait_event_timeout(priv->fence_event,
                                fence_completed(dev, fence),
                                remaining_jiffies);
 
@@ -853,7 +858,7 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       return msm_wait_fence_interruptable(dev, args->fence, &timeout);
+       return msm_wait_fence(dev, args->fence, &timeout, true);
 }
 
 static const struct drm_ioctl_desc msm_ioctls[] = {
index e7c5ea125d45ed42ebaa043522a88b4bcb2c2e3f..4ff0ec9c994b33f84421bd800e88abd8f7b3834a 100644 (file)
@@ -164,8 +164,8 @@ int msm_atomic_commit(struct drm_device *dev,
 
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
-int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
-               ktime_t *timeout);
+int msm_wait_fence(struct drm_device *dev, uint32_t fence,
+               ktime_t *timeout, bool interruptible);
 int msm_queue_fence_cb(struct drm_device *dev,
                struct msm_fence_cb *cb, uint32_t fence);
 void msm_update_fence(struct drm_device *dev, uint32_t fence);
index f211b80e3a1e0604489b1ed91a65e4e1b489b894..c76cc853b08a57effec626b8c6f537b270ca61ac 100644 (file)
@@ -460,7 +460,7 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
                if (op & MSM_PREP_NOSYNC)
                        timeout = NULL;
 
-               ret = msm_wait_fence_interruptable(dev, fence, timeout);
+               ret = msm_wait_fence(dev, fence, timeout, true);
        }
 
        /* TODO cache maintenance */
index dd7a7ab603e2c202ea297575fab0aba003234f5b..831461bc98a549e8a3627cbd1cf5a1b4a3250c7b 100644 (file)
 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
-       BUG_ON(!msm_obj->sgt);  /* should have already pinned! */
-       return msm_obj->sgt;
+       int npages = obj->size >> PAGE_SHIFT;
+
+       if (WARN_ON(!msm_obj->pages))  /* should have already pinned! */
+               return NULL;
+
+       return drm_prime_pages_to_sg(msm_obj->pages, npages);
 }
 
 void *msm_gem_prime_vmap(struct drm_gem_object *obj)
index 649024d4daf1da6e5aa1e074e303ba02ec312de0..477cbb12809b029c2de6d62bdd0bcb3ba415001c 100644 (file)
@@ -128,6 +128,7 @@ nouveau_cli_destroy(struct nouveau_cli *cli)
        nvkm_vm_ref(NULL, &nvxx_client(&cli->base)->vm, NULL);
        nvif_client_fini(&cli->base);
        usif_client_fini(cli);
+       kfree(cli);
 }
 
 static void
@@ -865,8 +866,10 @@ nouveau_drm_preclose(struct drm_device *dev, struct drm_file *fpriv)
 
        pm_runtime_get_sync(dev->dev);
 
+       mutex_lock(&cli->mutex);
        if (cli->abi16)
                nouveau_abi16_fini(cli->abi16);
+       mutex_unlock(&cli->mutex);
 
        mutex_lock(&drm->client.mutex);
        list_del(&cli->head);
index 775277f1edb0a4ae4c1a2862418827878710ddb8..dcfbbfaf1739781724e312a4fc15cded1298358d 100644 (file)
@@ -92,6 +92,8 @@ static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_IOMMU_API)
+
 static void nouveau_platform_probe_iommu(struct device *dev,
                                         struct nouveau_platform_gpu *gpu)
 {
@@ -158,6 +160,20 @@ static void nouveau_platform_remove_iommu(struct device *dev,
        }
 }
 
+#else
+
+static void nouveau_platform_probe_iommu(struct device *dev,
+                                        struct nouveau_platform_gpu *gpu)
+{
+}
+
+static void nouveau_platform_remove_iommu(struct device *dev,
+                                         struct nouveau_platform_gpu *gpu)
+{
+}
+
+#endif
+
 static int nouveau_platform_probe(struct platform_device *pdev)
 {
        struct nouveau_platform_gpu *gpu;
index 18f4497157885a897a9cbec14c390d397a02ca25..7464aef34674965bbf077570b703abf5bf2630e5 100644 (file)
@@ -175,15 +175,24 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
        node->page_shift = 12;
 
        switch (drm->device.info.family) {
+       case NV_DEVICE_INFO_V0_TNT:
+       case NV_DEVICE_INFO_V0_CELSIUS:
+       case NV_DEVICE_INFO_V0_KELVIN:
+       case NV_DEVICE_INFO_V0_RANKINE:
+       case NV_DEVICE_INFO_V0_CURIE:
+               break;
        case NV_DEVICE_INFO_V0_TESLA:
                if (drm->device.info.chipset != 0x50)
                        node->memtype = (nvbo->tile_flags & 0x7f00) >> 8;
                break;
        case NV_DEVICE_INFO_V0_FERMI:
        case NV_DEVICE_INFO_V0_KEPLER:
+       case NV_DEVICE_INFO_V0_MAXWELL:
                node->memtype = (nvbo->tile_flags & 0xff00) >> 8;
                break;
        default:
+               NV_WARN(drm, "%s: unhandled family type %x\n", __func__,
+                       drm->device.info.family);
                break;
        }
 
index 4ef602c5469d2563ee89d4153f0315abdc485a20..495c57644ced91e4a45c7b8b6205fff7d32ff8ae 100644 (file)
@@ -203,7 +203,7 @@ nv04_fbcon_accel_init(struct fb_info *info)
        if (ret)
                return ret;
 
-       if (RING_SPACE(chan, 49)) {
+       if (RING_SPACE(chan, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
                nouveau_fbcon_gpu_lockup(info);
                return 0;
        }
index 7da7958556a3abe68f94eac820c62aa8b41a923a..981342d142ff61b6c6292fc14399eb7a43ad08a6 100644 (file)
@@ -979,7 +979,7 @@ nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
 {
        struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
 
-       if (show && nv_crtc->cursor.nvbo)
+       if (show && nv_crtc->cursor.nvbo && nv_crtc->base.enabled)
                nv50_crtc_cursor_show(nv_crtc);
        else
                nv50_crtc_cursor_hide(nv_crtc);
index 394c89abcc97d92cf1b0352ea6e060b9ee011027..901130b0607291da4d08401f82e6ed05688c84b5 100644 (file)
@@ -188,7 +188,7 @@ nv50_fbcon_accel_init(struct fb_info *info)
        if (ret)
                return ret;
 
-       ret = RING_SPACE(chan, 59);
+       ret = RING_SPACE(chan, 58);
        if (ret) {
                nouveau_fbcon_gpu_lockup(info);
                return ret;
@@ -252,6 +252,7 @@ nv50_fbcon_accel_init(struct fb_info *info)
        OUT_RING(chan, info->var.yres_virtual);
        OUT_RING(chan, upper_32_bits(fb->vma.offset));
        OUT_RING(chan, lower_32_bits(fb->vma.offset));
+       FIRE_RING(chan);
 
        return 0;
 }
index 61246677e8dcdd901119a84d5bc4e6c09287978b..fcd2e5f27bb9539ba113e790222713b10127f825 100644 (file)
@@ -188,7 +188,7 @@ nvc0_fbcon_accel_init(struct fb_info *info)
                return -EINVAL;
        }
 
-       ret = RING_SPACE(chan, 60);
+       ret = RING_SPACE(chan, 58);
        if (ret) {
                WARN_ON(1);
                nouveau_fbcon_gpu_lockup(info);
index 9ef6728c528d999ef625a9c1472de95c0c02ba24..7f2f05f78cc8cb7a17e7c7f2445c741981c9389a 100644 (file)
@@ -809,7 +809,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
                case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
                default:
                        nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
-                       return 0x0000;
+                       return NULL;
                }
        }
 
index 5606c25e5d02998fc415a5b9705d9a40868f2a10..ca11ddb6ed467588ebe5cb98e359b91e07da92c4 100644 (file)
@@ -663,6 +663,37 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv)
                gf100_gr_zbc_clear_depth(priv, index);
 }
 
+/**
+ * Wait until GR goes idle. GR is considered idle if it is disabled by the
+ * MC (0x200) register, or GR is not busy and a context switch is not in
+ * progress.
+ */
+int
+gf100_gr_wait_idle(struct gf100_gr_priv *priv)
+{
+       unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000);
+       bool gr_enabled, ctxsw_active, gr_busy;
+
+       do {
+               /*
+                * required to make sure FIFO_ENGINE_STATUS (0x2640) is
+                * up-to-date
+                */
+               nv_rd32(priv, 0x400700);
+
+               gr_enabled = nv_rd32(priv, 0x200) & 0x1000;
+               ctxsw_active = nv_rd32(priv, 0x2640) & 0x8000;
+               gr_busy = nv_rd32(priv, 0x40060c) & 0x1;
+
+               if (!gr_enabled || (!gr_busy && !ctxsw_active))
+                       return 0;
+       } while (time_before(jiffies, end_jiffies));
+
+       nv_error(priv, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n",
+                gr_enabled, ctxsw_active, gr_busy);
+       return -EAGAIN;
+}
+
 void
 gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
 {
@@ -699,7 +730,13 @@ gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
 
                while (addr < next) {
                        nv_wr32(priv, 0x400200, addr);
-                       nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
+                       /**
+                        * Wait for GR to go idle after submitting a
+                        * GO_IDLE bundle
+                        */
+                       if ((addr & 0xffff) == 0xe100)
+                               gf100_gr_wait_idle(priv);
+                       nv_wait(priv, 0x400700, 0x00000004, 0x00000000);
                        addr += init->pitch;
                }
        }
index 8af1a89eda84d13436b0345301a3e767cc710c19..c9533fdac4fc85a2b0189429d6564cbc119734a7 100644 (file)
@@ -181,6 +181,7 @@ struct gf100_gr_oclass {
        int ppc_nr;
 };
 
+int  gf100_gr_wait_idle(struct gf100_gr_priv *);
 void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *);
 void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
 void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
index 2006c445938d9493773ef2dbf9bb07d045a67b96..4cf36a3aa81460c2c062b6cc41e70571530c1eb8 100644 (file)
@@ -332,9 +332,12 @@ static void
 nvkm_perfctx_dtor(struct nvkm_object *object)
 {
        struct nvkm_pm *ppm = (void *)object->engine;
+       struct nvkm_perfctx *ctx = (void *)object;
+
        mutex_lock(&nv_subdev(ppm)->mutex);
-       nvkm_engctx_destroy(&ppm->context->base);
-       ppm->context = NULL;
+       nvkm_engctx_destroy(&ctx->base);
+       if (ppm->context == ctx)
+               ppm->context = NULL;
        mutex_unlock(&nv_subdev(ppm)->mutex);
 }
 
@@ -355,12 +358,11 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        mutex_lock(&nv_subdev(ppm)->mutex);
        if (ppm->context == NULL)
                ppm->context = ctx;
-       mutex_unlock(&nv_subdev(ppm)->mutex);
-
        if (ctx != ppm->context)
-               return -EBUSY;
+               ret = -EBUSY;
+       mutex_unlock(&nv_subdev(ppm)->mutex);
 
-       return 0;
+       return ret;
 }
 
 struct nvkm_oclass
index f67cdae1e90a599a04c46dd7a654102a7731bdf0..f4611e3f097187002e68dc54af44c45bfd0006d9 100644 (file)
@@ -1284,6 +1284,44 @@ init_zm_reg_sequence(struct nvbios_init *init)
        }
 }
 
+/**
+ * INIT_PLL_INDIRECT - opcode 0x59
+ *
+ */
+static void
+init_pll_indirect(struct nvbios_init *init)
+{
+       struct nvkm_bios *bios = init->bios;
+       u32  reg = nv_ro32(bios, init->offset + 1);
+       u16 addr = nv_ro16(bios, init->offset + 5);
+       u32 freq = (u32)nv_ro16(bios, addr) * 1000;
+
+       trace("PLL_INDIRECT\tR[0x%06x] =PLL= VBIOS[%04x] = %dkHz\n",
+             reg, addr, freq);
+       init->offset += 7;
+
+       init_prog_pll(init, reg, freq);
+}
+
+/**
+ * INIT_ZM_REG_INDIRECT - opcode 0x5a
+ *
+ */
+static void
+init_zm_reg_indirect(struct nvbios_init *init)
+{
+       struct nvkm_bios *bios = init->bios;
+       u32  reg = nv_ro32(bios, init->offset + 1);
+       u16 addr = nv_ro16(bios, init->offset + 5);
+       u32 data = nv_ro32(bios, addr);
+
+       trace("ZM_REG_INDIRECT\tR[0x%06x] = VBIOS[0x%04x] = 0x%08x\n",
+             reg, addr, data);
+       init->offset += 7;
+
+       init_wr32(init, addr, data);
+}
+
 /**
  * INIT_SUB_DIRECT - opcode 0x5b
  *
@@ -2145,6 +2183,8 @@ static struct nvbios_init_opcode {
        [0x56] = { init_condition_time },
        [0x57] = { init_ltime },
        [0x58] = { init_zm_reg_sequence },
+       [0x59] = { init_pll_indirect },
+       [0x5a] = { init_zm_reg_indirect },
        [0x5b] = { init_sub_direct },
        [0x5c] = { init_jump },
        [0x5e] = { init_i2c_if },
index 822d32a28d6e15a38f8c9db722288c27c9349d41..065e9f5c8db98a0a2b70b5b2d4a203d350899465 100644 (file)
@@ -180,7 +180,8 @@ gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz,
               struct gt215_clk_info *info)
 {
        struct gt215_clk_priv *priv = (void *)clock;
-       u32 oclk, sclk, sdiv, diff;
+       u32 oclk, sclk, sdiv;
+       s32 diff;
 
        info->clk = 0;
 
index c0fdb89e74ac4a41944e2d7c2f41ca3daa6c4ed6..24dcdfb58a8d852039317a5017ee34dcc9cf3039 100644 (file)
@@ -38,6 +38,14 @@ gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv)
        nv_wr32(priv, 0x12004c, 0x4);
        nv_wr32(priv, 0x122204, 0x2);
        nv_rd32(priv, 0x122204);
+
+       /*
+        * Bug: increase clock timeout to avoid operation failure at high
+        * gpcclk rate.
+        */
+       nv_wr32(priv, 0x122354, 0x800);
+       nv_wr32(priv, 0x128328, 0x800);
+       nv_wr32(priv, 0x124320, 0x800);
 }
 
 static void
index 80614f1b207474ae407251d6811add96925e8241..282143f49d72e60ba5c66f79fc818ca3b37ea942 100644 (file)
@@ -50,7 +50,12 @@ nv04_instobj_dtor(struct nvkm_object *object)
 {
        struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
        struct nv04_instobj_priv *node = (void *)object;
+       struct nvkm_subdev *subdev = (void *)priv;
+
+       mutex_lock(&subdev->mutex);
        nvkm_mm_free(&priv->heap, &node->mem);
+       mutex_unlock(&subdev->mutex);
+
        nvkm_instobj_destroy(&node->base);
 }
 
@@ -62,6 +67,7 @@ nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent);
        struct nv04_instobj_priv *node;
        struct nvkm_instobj_args *args = data;
+       struct nvkm_subdev *subdev = (void *)priv;
        int ret;
 
        if (!args->align)
@@ -72,8 +78,10 @@ nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
        if (ret)
                return ret;
 
+       mutex_lock(&subdev->mutex);
        ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size,
                           args->align, &node->mem);
+       mutex_unlock(&subdev->mutex);
        if (ret)
                return ret;
 
index f2daad8c3d960e2eba99d55f996ba658a0a97227..7841970de48d19e10bc23a0bde4a2388b05708f5 100644 (file)
@@ -285,7 +285,7 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
 
        if (wait) {
                if (!wait_for_completion_timeout(&engine->compl,
-                               msecs_to_jiffies(1))) {
+                               msecs_to_jiffies(100))) {
                        dev_err(dmm->dev, "timed out waiting for done\n");
                        ret = -ETIMEDOUT;
                }
index ae2df41f216f04652b8d18817ee80e9fddd41147..12081e61d45a99b02956bda4dc5759036ef64d23 100644 (file)
@@ -177,7 +177,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
                struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
 int omap_framebuffer_pin(struct drm_framebuffer *fb);
-int omap_framebuffer_unpin(struct drm_framebuffer *fb);
+void omap_framebuffer_unpin(struct drm_framebuffer *fb);
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
                struct omap_drm_window *win, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
@@ -211,7 +211,7 @@ void omap_gem_dma_sync(struct drm_gem_object *obj,
                enum dma_data_direction dir);
 int omap_gem_get_paddr(struct drm_gem_object *obj,
                dma_addr_t *paddr, bool remap);
-int omap_gem_put_paddr(struct drm_gem_object *obj);
+void omap_gem_put_paddr(struct drm_gem_object *obj);
 int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
                bool remap);
 int omap_gem_put_pages(struct drm_gem_object *obj);
@@ -236,7 +236,7 @@ static inline int align_pitch(int pitch, int width, int bpp)
        /* PVR needs alignment to 8 pixels.. right now that is the most
         * restrictive stride requirement..
         */
-       return ALIGN(pitch, 8 * bytespp);
+       return roundup(pitch, 8 * bytespp);
 }
 
 /* map crtc to vblank mask */
index 0b967e76df1a875a9f8139b6a2482e5997965412..51b1219af87f1b29fbbe641fa2fbfd51b5c3b92d 100644 (file)
@@ -287,10 +287,10 @@ fail:
 }
 
 /* unpin, no longer being scanned out: */
-int omap_framebuffer_unpin(struct drm_framebuffer *fb)
+void omap_framebuffer_unpin(struct drm_framebuffer *fb)
 {
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-       int ret, i, n = drm_format_num_planes(fb->pixel_format);
+       int i, n = drm_format_num_planes(fb->pixel_format);
 
        mutex_lock(&omap_fb->lock);
 
@@ -298,24 +298,16 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
 
        if (omap_fb->pin_count > 0) {
                mutex_unlock(&omap_fb->lock);
-               return 0;
+               return;
        }
 
        for (i = 0; i < n; i++) {
                struct plane *plane = &omap_fb->planes[i];
-               ret = omap_gem_put_paddr(plane->bo);
-               if (ret)
-                       goto fail;
+               omap_gem_put_paddr(plane->bo);
                plane->paddr = 0;
        }
 
        mutex_unlock(&omap_fb->lock);
-
-       return 0;
-
-fail:
-       mutex_unlock(&omap_fb->lock);
-       return ret;
 }
 
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p)
index 23b5a84389e3b23b0245af9146128862c571b639..720d16bce7e82b790a7aff17f5bbec94b6df18fe 100644 (file)
@@ -135,7 +135,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
        fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled;
        if (fbdev->ywrap_enabled) {
                /* need to align pitch to page size if using DMM scrolling */
-               mode_cmd.pitches[0] = ALIGN(mode_cmd.pitches[0], PAGE_SIZE);
+               mode_cmd.pitches[0] = PAGE_ALIGN(mode_cmd.pitches[0]);
        }
 
        /* allocate backing bo */
index 2ab77801cf5f070ab08bc5f8255c6126291b94b3..7ed08fdc4c4285eff29f109ce67de4b79e970de2 100644 (file)
@@ -808,10 +808,10 @@ fail:
 /* Release physical address, when DMA is no longer being performed.. this
  * could potentially unpin and unmap buffers from TILER
  */
-int omap_gem_put_paddr(struct drm_gem_object *obj)
+void omap_gem_put_paddr(struct drm_gem_object *obj)
 {
        struct omap_gem_object *omap_obj = to_omap_bo(obj);
-       int ret = 0;
+       int ret;
 
        mutex_lock(&obj->dev->struct_mutex);
        if (omap_obj->paddr_cnt > 0) {
@@ -821,7 +821,6 @@ int omap_gem_put_paddr(struct drm_gem_object *obj)
                        if (ret) {
                                dev_err(obj->dev->dev,
                                        "could not unpin pages: %d\n", ret);
-                               goto fail;
                        }
                        ret = tiler_release(omap_obj->block);
                        if (ret) {
@@ -832,9 +831,8 @@ int omap_gem_put_paddr(struct drm_gem_object *obj)
                        omap_obj->block = NULL;
                }
        }
-fail:
+
        mutex_unlock(&obj->dev->struct_mutex);
-       return ret;
 }
 
 /* Get rotated scanout address (only valid if already pinned), at the
@@ -1378,11 +1376,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
 
        omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL);
        if (!omap_obj)
-               goto fail;
-
-       spin_lock(&priv->list_lock);
-       list_add(&omap_obj->mm_list, &priv->obj_list);
-       spin_unlock(&priv->list_lock);
+               return NULL;
 
        obj = &omap_obj->base;
 
@@ -1392,11 +1386,19 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
                 */
                omap_obj->vaddr =  dma_alloc_writecombine(dev->dev, size,
                                &omap_obj->paddr, GFP_KERNEL);
-               if (omap_obj->vaddr)
-                       flags |= OMAP_BO_DMA;
+               if (!omap_obj->vaddr) {
+                       kfree(omap_obj);
+
+                       return NULL;
+               }
 
+               flags |= OMAP_BO_DMA;
        }
 
+       spin_lock(&priv->list_lock);
+       list_add(&omap_obj->mm_list, &priv->obj_list);
+       spin_unlock(&priv->list_lock);
+
        omap_obj->flags = flags;
 
        if (flags & OMAP_BO_TILED) {
index cfa8276c4debafe4286f424f300936bbc42f009a..098904696a5cada72fab1e4f221ce7621af197a5 100644 (file)
@@ -17,6 +17,7 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 
@@ -153,9 +154,34 @@ static void omap_plane_atomic_disable(struct drm_plane *plane,
        dispc_ovl_enable(omap_plane->id, false);
 }
 
+static int omap_plane_atomic_check(struct drm_plane *plane,
+                                  struct drm_plane_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+
+       if (!state->crtc)
+               return 0;
+
+       crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+       if (IS_ERR(crtc_state))
+               return PTR_ERR(crtc_state);
+
+       if (state->crtc_x < 0 || state->crtc_y < 0)
+               return -EINVAL;
+
+       if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
+               return -EINVAL;
+
+       if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
+               return -EINVAL;
+
+       return 0;
+}
+
 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
        .prepare_fb = omap_plane_prepare_fb,
        .cleanup_fb = omap_plane_cleanup_fb,
+       .atomic_check = omap_plane_atomic_check,
        .atomic_update = omap_plane_atomic_update,
        .atomic_disable = omap_plane_atomic_disable,
 };
index dd39f434b4a7eccf1446ff5cd1857a2cf5de972d..c3872598b85a3856787b1bf0b7113633a468e020 100644 (file)
@@ -2299,8 +2299,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        encoder_mode = atombios_get_encoder_mode(encoder);
        if (connector && (radeon_audio != 0) &&
            ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
-            (ENCODER_MODE_IS_DP(encoder_mode) &&
-             drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+            ENCODER_MODE_IS_DP(encoder_mode)))
                radeon_audio_mode_set(encoder, adjusted_mode);
 }
 
index 8730562323a8b77d0dd86ec399207806a6807ddc..4a09947be24457fed430abeaf0fa308938574413 100644 (file)
@@ -5818,7 +5818,7 @@ int ci_dpm_init(struct radeon_device *rdev)
                        tmp |= DPM_ENABLED;
                        break;
                default:
-                       DRM_ERROR("Invalid PCC GPIO: %u!\n", gpio.shift);
+                       DRM_DEBUG("Invalid PCC GPIO: %u!\n", gpio.shift);
                        break;
                }
                WREG32_SMC(CNB_PWRMGT_CNTL, tmp);
index 4ecf5caa8c6d9745f9421710179aa2f81ef3587f..248953d2fdb742d69111193f62638c0a95f179d5 100644 (file)
@@ -7964,23 +7964,27 @@ restart_ih:
                case 1: /* D1 vblank/vline */
                        switch (src_data) {
                        case 0: /* D1 vblank */
-                               if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[0]) {
-                                               drm_handle_vblank(rdev->ddev, 0);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[0]))
-                                               radeon_crtc_handle_vblank(rdev, 0);
-                                       rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vblank\n");
+                               if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[0]) {
+                                       drm_handle_vblank(rdev->ddev, 0);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[0]))
+                                       radeon_crtc_handle_vblank(rdev, 0);
+                               rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vblank\n");
+
                                break;
                        case 1: /* D1 vline */
-                               if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -7990,23 +7994,27 @@ restart_ih:
                case 2: /* D2 vblank/vline */
                        switch (src_data) {
                        case 0: /* D2 vblank */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[1]) {
-                                               drm_handle_vblank(rdev->ddev, 1);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[1]))
-                                               radeon_crtc_handle_vblank(rdev, 1);
-                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vblank\n");
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[1]) {
+                                       drm_handle_vblank(rdev->ddev, 1);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[1]))
+                                       radeon_crtc_handle_vblank(rdev, 1);
+                               rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vblank\n");
+
                                break;
                        case 1: /* D2 vline */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -8016,23 +8024,27 @@ restart_ih:
                case 3: /* D3 vblank/vline */
                        switch (src_data) {
                        case 0: /* D3 vblank */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[2]) {
-                                               drm_handle_vblank(rdev->ddev, 2);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[2]))
-                                               radeon_crtc_handle_vblank(rdev, 2);
-                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D3 vblank\n");
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[2]) {
+                                       drm_handle_vblank(rdev->ddev, 2);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[2]))
+                                       radeon_crtc_handle_vblank(rdev, 2);
+                               rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D3 vblank\n");
+
                                break;
                        case 1: /* D3 vline */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D3 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D3 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -8042,23 +8054,27 @@ restart_ih:
                case 4: /* D4 vblank/vline */
                        switch (src_data) {
                        case 0: /* D4 vblank */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[3]) {
-                                               drm_handle_vblank(rdev->ddev, 3);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[3]))
-                                               radeon_crtc_handle_vblank(rdev, 3);
-                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D4 vblank\n");
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[3]) {
+                                       drm_handle_vblank(rdev->ddev, 3);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[3]))
+                                       radeon_crtc_handle_vblank(rdev, 3);
+                               rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D4 vblank\n");
+
                                break;
                        case 1: /* D4 vline */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D4 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D4 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -8068,23 +8084,27 @@ restart_ih:
                case 5: /* D5 vblank/vline */
                        switch (src_data) {
                        case 0: /* D5 vblank */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[4]) {
-                                               drm_handle_vblank(rdev->ddev, 4);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[4]))
-                                               radeon_crtc_handle_vblank(rdev, 4);
-                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D5 vblank\n");
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[4]) {
+                                       drm_handle_vblank(rdev->ddev, 4);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[4]))
+                                       radeon_crtc_handle_vblank(rdev, 4);
+                               rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D5 vblank\n");
+
                                break;
                        case 1: /* D5 vline */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D5 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D5 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -8094,23 +8114,27 @@ restart_ih:
                case 6: /* D6 vblank/vline */
                        switch (src_data) {
                        case 0: /* D6 vblank */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[5]) {
-                                               drm_handle_vblank(rdev->ddev, 5);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[5]))
-                                               radeon_crtc_handle_vblank(rdev, 5);
-                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D6 vblank\n");
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[5]) {
+                                       drm_handle_vblank(rdev->ddev, 5);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[5]))
+                                       radeon_crtc_handle_vblank(rdev, 5);
+                               rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D6 vblank\n");
+
                                break;
                        case 1: /* D6 vline */
-                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D6 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D6 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -8130,88 +8154,112 @@ restart_ih:
                case 42: /* HPD hotplug */
                        switch (src_data) {
                        case 0:
-                               if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD1\n");
+
                                break;
                        case 1:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD2\n");
+
                                break;
                        case 2:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD3\n");
+
                                break;
                        case 3:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD4\n");
+
                                break;
                        case 4:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD5\n");
+
                                break;
                        case 5:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD6\n");
+
                                break;
                        case 6:
-                               if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 1\n");
+
                                break;
                        case 7:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 2\n");
+
                                break;
                        case 8:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 3\n");
+
                                break;
                        case 9:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 4\n");
+
                                break;
                        case 10:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 5\n");
+
                                break;
                        case 11:
-                               if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 6\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
index 68fd9fc677e35f1ca161295694301ec21c089e4d..44480c1b9738cc2625cee481ccf02aa20ed6bb1f 100644 (file)
@@ -93,30 +93,26 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 offset;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->offset;
-
-       WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
-              AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
+       WREG32(AFMT_AUDIO_SRC_CONTROL +  dig->afmt->offset,
+              AFMT_AUDIO_SRC_SELECT(dig->pin->id));
 }
 
 void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
-               struct drm_connector *connector, struct drm_display_mode *mode)
+                                   struct drm_connector *connector,
+                                   struct drm_display_mode *mode)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 tmp = 0, offset;
+       u32 tmp = 0;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
                if (connector->latency_present[1])
                        tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
@@ -130,24 +126,24 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
                else
                        tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0);
        }
-       WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
+       WREG32_ENDPOINT(dig->pin->offset,
+                       AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
 }
 
 void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
-       u8 *sadb, int sad_count)
+                                            u8 *sadb, int sad_count)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 offset, tmp;
+       u32 tmp;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        /* program the speaker allocation */
-       tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+       tmp = RREG32_ENDPOINT(dig->pin->offset,
+                             AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
        tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
        /* set HDMI mode */
        tmp |= HDMI_CONNECTION;
@@ -155,24 +151,24 @@ void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
                tmp |= SPEAKER_ALLOCATION(sadb[0]);
        else
                tmp |= SPEAKER_ALLOCATION(5); /* stereo */
-       WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+       WREG32_ENDPOINT(dig->pin->offset,
+                       AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
 }
 
 void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
-       u8 *sadb, int sad_count)
+                                          u8 *sadb, int sad_count)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       u32 offset, tmp;
+       u32 tmp;
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        /* program the speaker allocation */
-       tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+       tmp = RREG32_ENDPOINT(dig->pin->offset,
+                             AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
        tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
        /* set DP mode */
        tmp |= DP_CONNECTION;
@@ -180,13 +176,13 @@ void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
                tmp |= SPEAKER_ALLOCATION(sadb[0]);
        else
                tmp |= SPEAKER_ALLOCATION(5); /* stereo */
-       WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+       WREG32_ENDPOINT(dig->pin->offset,
+                       AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
 }
 
 void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
-       struct cea_sad *sads, int sad_count)
+                             struct cea_sad *sads, int sad_count)
 {
-       u32 offset;
        int i;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
@@ -206,11 +202,9 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
                { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
        };
 
-       if (!dig || !dig->afmt || !dig->afmt->pin)
+       if (!dig || !dig->afmt || !dig->pin)
                return;
 
-       offset = dig->afmt->pin->offset;
-
        for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
                u32 value = 0;
                u8 stereo_freqs = 0;
@@ -237,7 +231,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
 
                value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
 
-               WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
+               WREG32_ENDPOINT(dig->pin->offset, eld_reg_to_type[i][0], value);
        }
 }
 
@@ -253,7 +247,7 @@ void dce6_audio_enable(struct radeon_device *rdev,
 }
 
 void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                            struct radeon_crtc *crtc, unsigned int clock)
 {
        /* Two dtos; generally use dto0 for HDMI */
        u32 value = 0;
@@ -272,7 +266,7 @@ void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
 }
 
 void dce6_dp_audio_set_dto(struct radeon_device *rdev,
-       struct radeon_crtc *crtc, unsigned int clock)
+                          struct radeon_crtc *crtc, unsigned int clock)
 {
        /* Two dtos; generally use dto1 for DP */
        u32 value = 0;
index 3a6d483a2c36a75cd52edecdb58928404629567a..0acde1949c18d4bcc52790754ab41f3ae74ffd6f 100644 (file)
@@ -4924,7 +4924,7 @@ restart_ih:
                return IRQ_NONE;
 
        rptr = rdev->ih.rptr;
-       DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+       DRM_DEBUG("evergreen_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
 
        /* Order reading of wptr vs. reading of IH ring data */
        rmb();
@@ -4942,23 +4942,27 @@ restart_ih:
                case 1: /* D1 vblank/vline */
                        switch (src_data) {
                        case 0: /* D1 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[0]) {
-                                               drm_handle_vblank(rdev->ddev, 0);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[0]))
-                                               radeon_crtc_handle_vblank(rdev, 0);
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[0]) {
+                                       drm_handle_vblank(rdev->ddev, 0);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[0]))
+                                       radeon_crtc_handle_vblank(rdev, 0);
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vblank\n");
+
                                break;
                        case 1: /* D1 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -4968,23 +4972,27 @@ restart_ih:
                case 2: /* D2 vblank/vline */
                        switch (src_data) {
                        case 0: /* D2 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[1]) {
-                                               drm_handle_vblank(rdev->ddev, 1);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[1]))
-                                               radeon_crtc_handle_vblank(rdev, 1);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[1]) {
+                                       drm_handle_vblank(rdev->ddev, 1);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[1]))
+                                       radeon_crtc_handle_vblank(rdev, 1);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vblank\n");
+
                                break;
                        case 1: /* D2 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -4994,23 +5002,27 @@ restart_ih:
                case 3: /* D3 vblank/vline */
                        switch (src_data) {
                        case 0: /* D3 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[2]) {
-                                               drm_handle_vblank(rdev->ddev, 2);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[2]))
-                                               radeon_crtc_handle_vblank(rdev, 2);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D3 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D3 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[2]) {
+                                       drm_handle_vblank(rdev->ddev, 2);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[2]))
+                                       radeon_crtc_handle_vblank(rdev, 2);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D3 vblank\n");
+
                                break;
                        case 1: /* D3 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D3 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D3 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D3 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -5020,23 +5032,27 @@ restart_ih:
                case 4: /* D4 vblank/vline */
                        switch (src_data) {
                        case 0: /* D4 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[3]) {
-                                               drm_handle_vblank(rdev->ddev, 3);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[3]))
-                                               radeon_crtc_handle_vblank(rdev, 3);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D4 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D4 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[3]) {
+                                       drm_handle_vblank(rdev->ddev, 3);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[3]))
+                                       radeon_crtc_handle_vblank(rdev, 3);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D4 vblank\n");
+
                                break;
                        case 1: /* D4 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D4 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D4 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D4 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -5046,23 +5062,27 @@ restart_ih:
                case 5: /* D5 vblank/vline */
                        switch (src_data) {
                        case 0: /* D5 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[4]) {
-                                               drm_handle_vblank(rdev->ddev, 4);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[4]))
-                                               radeon_crtc_handle_vblank(rdev, 4);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D5 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D5 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[4]) {
+                                       drm_handle_vblank(rdev->ddev, 4);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[4]))
+                                       radeon_crtc_handle_vblank(rdev, 4);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D5 vblank\n");
+
                                break;
                        case 1: /* D5 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D5 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D5 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D5 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -5072,23 +5092,27 @@ restart_ih:
                case 6: /* D6 vblank/vline */
                        switch (src_data) {
                        case 0: /* D6 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[5]) {
-                                               drm_handle_vblank(rdev->ddev, 5);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[5]))
-                                               radeon_crtc_handle_vblank(rdev, 5);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D6 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D6 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[5]) {
+                                       drm_handle_vblank(rdev->ddev, 5);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[5]))
+                                       radeon_crtc_handle_vblank(rdev, 5);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D6 vblank\n");
+
                                break;
                        case 1: /* D6 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D6 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D6 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D6 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -5108,88 +5132,100 @@ restart_ih:
                case 42: /* HPD hotplug */
                        switch (src_data) {
                        case 0:
-                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD1\n");
                                break;
                        case 1:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD2\n");
                                break;
                        case 2:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD3\n");
                                break;
                        case 3:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD4\n");
                                break;
                        case 4:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD5\n");
                                break;
                        case 5:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD6\n");
                                break;
                        case 6:
-                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 1\n");
                                break;
                        case 7:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 2\n");
                                break;
                        case 8:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 3\n");
                                break;
                        case 9:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 4\n");
                                break;
                        case 10:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 5\n");
                                break;
                        case 11:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 6\n");
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -5199,46 +5235,52 @@ restart_ih:
                case 44: /* hdmi */
                        switch (src_data) {
                        case 0:
-                               if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI0\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI0\n");
                                break;
                        case 1:
-                               if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI1\n");
                                break;
                        case 2:
-                               if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI2\n");
                                break;
                        case 3:
-                               if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI3\n");
                                break;
                        case 4:
-                               if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI4\n");
                                break;
                        case 5:
-                               if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI5\n");
                                break;
                        default:
                                DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
index 8e5aeeb058a5a59d3bd8fa65937d7b652d853bb8..158872eb78e41ae94276b1abdad3fdce76ef463f 100644 (file)
@@ -2162,18 +2162,20 @@ static int cayman_startup(struct radeon_device *rdev)
                        DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
        }
 
-       ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
-       if (ring->ring_size)
-               r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
+       if (rdev->family == CHIP_ARUBA) {
+               ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
+               if (ring->ring_size)
+                       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
 
-       ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
-       if (ring->ring_size)
-               r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
+               ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
+               if (ring->ring_size)
+                       r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0);
 
-       if (!r)
-               r = vce_v1_0_init(rdev);
-       else if (r != -ENOENT)
-               DRM_ERROR("radeon: failed initializing VCE (%d).\n", r);
+               if (!r)
+                       r = vce_v1_0_init(rdev);
+               if (r)
+                       DRM_ERROR("radeon: failed initializing VCE (%d).\n", r);
+       }
 
        r = radeon_ib_pool_init(rdev);
        if (r) {
@@ -2396,7 +2398,8 @@ void cayman_fini(struct radeon_device *rdev)
        radeon_irq_kms_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
-       radeon_vce_fini(rdev);
+       if (rdev->family == CHIP_ARUBA)
+               radeon_vce_fini(rdev);
        cayman_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
index 35dafd77a639f0fbf404671ea348049f51bfaa9c..4ea5b10ff5f412fb0fc2b161c8fe936ab154bd2f 100644 (file)
@@ -4086,23 +4086,27 @@ restart_ih:
                case 1: /* D1 vblank/vline */
                        switch (src_data) {
                        case 0: /* D1 vblank */
-                               if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[0]) {
-                                               drm_handle_vblank(rdev->ddev, 0);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[0]))
-                                               radeon_crtc_handle_vblank(rdev, 0);
-                                       rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vblank\n");
+                               if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[0]) {
+                                       drm_handle_vblank(rdev->ddev, 0);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[0]))
+                                       radeon_crtc_handle_vblank(rdev, 0);
+                               rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vblank\n");
+
                                break;
                        case 1: /* D1 vline */
-                               if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT))
+                                   DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -4112,23 +4116,27 @@ restart_ih:
                case 5: /* D2 vblank/vline */
                        switch (src_data) {
                        case 0: /* D2 vblank */
-                               if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[1]) {
-                                               drm_handle_vblank(rdev->ddev, 1);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[1]))
-                                               radeon_crtc_handle_vblank(rdev, 1);
-                                       rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vblank\n");
+                               if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[1]) {
+                                       drm_handle_vblank(rdev->ddev, 1);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[1]))
+                                       radeon_crtc_handle_vblank(rdev, 1);
+                               rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vblank\n");
+
                                break;
                        case 1: /* D1 vline */
-                               if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -4148,46 +4156,53 @@ restart_ih:
                case 19: /* HPD/DAC hotplug */
                        switch (src_data) {
                        case 0:
-                               if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT))
+                                       DRM_DEBUG("IH: HPD1 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD1\n");
                                break;
                        case 1:
-                               if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT))
+                                       DRM_DEBUG("IH: HPD2 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD2\n");
                                break;
                        case 4:
-                               if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT))
+                                       DRM_DEBUG("IH: HPD3 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD3\n");
                                break;
                        case 5:
-                               if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT))
+                                       DRM_DEBUG("IH: HPD4 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD4\n");
                                break;
                        case 10:
-                               if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT))
+                                       DRM_DEBUG("IH: HPD5 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD5\n");
                                break;
                        case 12:
-                               if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) {
-                                       rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT))
+                                       DRM_DEBUG("IH: HPD6 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD6\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -4197,18 +4212,22 @@ restart_ih:
                case 21: /* hdmi */
                        switch (src_data) {
                        case 4:
-                               if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI0\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: HDMI0 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI0\n");
+
                                break;
                        case 5:
-                               if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
-                                       rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG;
-                                       queue_hdmi = true;
-                                       DRM_DEBUG("IH: HDMI1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG))
+                                       DRM_DEBUG("IH: HDMI1 - IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG;
+                               queue_hdmi = true;
+                               DRM_DEBUG("IH: HDMI1\n");
+
                                break;
                        default:
                                DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
index 09e3f39925faa832661e59333bed740981c10621..98f9adaccc3dadfc75c85ff5a7cbdf9994e48abc 100644 (file)
@@ -2483,7 +2483,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev,
        struct drm_buf *buf;
        u32 *buffer;
        const u8 __user *data;
-       int size, pass_size;
+       unsigned int size, pass_size;
        u64 src_offset, dst_offset;
 
        if (!radeon_check_offset(dev_priv, tex->offset)) {
index fa719c53449bcd90e009e1b59d1b3e1ed5bff6f3..fbc8d88d6e5de1afe43c11884340e90bfa8e57a2 100644 (file)
@@ -245,6 +245,28 @@ static struct radeon_audio_funcs dce6_dp_funcs = {
 static void radeon_audio_enable(struct radeon_device *rdev,
                                struct r600_audio_pin *pin, u8 enable_mask)
 {
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       struct radeon_encoder_atom_dig *dig;
+       int pin_count = 0;
+
+       if (!pin)
+               return;
+
+       if (rdev->mode_info.mode_config_initialized) {
+               list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
+                       if (radeon_encoder_is_digital(encoder)) {
+                               radeon_encoder = to_radeon_encoder(encoder);
+                               dig = radeon_encoder->enc_priv;
+                               if (dig->pin == pin)
+                                       pin_count++;
+                       }
+               }
+
+               if ((pin_count > 1) && (enable_mask == 0))
+                       return;
+       }
+
        if (rdev->audio.funcs->enable)
                rdev->audio.funcs->enable(rdev, pin, enable_mask);
 }
@@ -336,24 +358,13 @@ void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
 
 static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
 {
-       struct radeon_encoder *radeon_encoder;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = NULL;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct cea_sad *sads;
        int sad_count;
 
-       list_for_each_entry(connector,
-               &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
-
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
+       if (!connector)
                return;
-       }
 
        sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
        if (sad_count <= 0) {
@@ -362,8 +373,6 @@ static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
        }
        BUG_ON(!sads);
 
-       radeon_encoder = to_radeon_encoder(encoder);
-
        if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
                radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
 
@@ -372,27 +381,16 @@ static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
 
 static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
 {
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = NULL;
        u8 *sadb = NULL;
        int sad_count;
 
-       list_for_each_entry(connector,
-                           &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
-
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
+       if (!connector)
                return;
-       }
 
-       sad_count = drm_edid_to_speaker_allocation(
-               radeon_connector_edid(connector), &sadb);
+       sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector),
+                                                  &sadb);
        if (sad_count < 0) {
                DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
                          sad_count);
@@ -406,26 +404,13 @@ static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
 }
 
 static void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                             struct drm_display_mode *mode)
 {
-       struct radeon_encoder *radeon_encoder;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = 0;
-
-       list_for_each_entry(connector,
-               &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
+       if (!connector)
                return;
-       }
-
-       radeon_encoder = to_radeon_encoder(encoder);
 
        if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
                radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
@@ -451,29 +436,23 @@ static void radeon_audio_select_pin(struct drm_encoder *encoder)
 }
 
 void radeon_audio_detect(struct drm_connector *connector,
+                        struct drm_encoder *encoder,
                         enum drm_connector_status status)
 {
-       struct radeon_device *rdev;
-       struct radeon_encoder *radeon_encoder;
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig;
 
-       if (!connector || !connector->encoder)
+       if (!radeon_audio_chipset_supported(rdev))
                return;
 
-       rdev = connector->encoder->dev->dev_private;
-
-       if (!radeon_audio_chipset_supported(rdev))
+       if (!radeon_encoder_is_digital(encoder))
                return;
 
-       radeon_encoder = to_radeon_encoder(connector->encoder);
        dig = radeon_encoder->enc_priv;
 
        if (status == connector_status_connected) {
-               if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) {
-                       radeon_encoder->audio = NULL;
-                       return;
-               }
-
                if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
@@ -486,11 +465,17 @@ void radeon_audio_detect(struct drm_connector *connector,
                        radeon_encoder->audio = rdev->audio.hdmi_funcs;
                }
 
-               dig->afmt->pin = radeon_audio_get_pin(connector->encoder);
-               radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+               if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+                       if (!dig->pin)
+                               dig->pin = radeon_audio_get_pin(encoder);
+                       radeon_audio_enable(rdev, dig->pin, 0xf);
+               } else {
+                       radeon_audio_enable(rdev, dig->pin, 0);
+                       dig->pin = NULL;
+               }
        } else {
-               radeon_audio_enable(rdev, dig->afmt->pin, 0);
-               dig->afmt->pin = NULL;
+               radeon_audio_enable(rdev, dig->pin, 0);
+               dig->pin = NULL;
        }
 }
 
@@ -518,29 +503,18 @@ static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock
 }
 
 static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                      struct drm_display_mode *mode)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector = NULL;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
        struct hdmi_avi_infoframe frame;
        int err;
 
-       list_for_each_entry(connector,
-               &encoder->dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       radeon_connector = to_radeon_connector(connector);
-                       break;
-               }
-       }
-
-       if (!radeon_connector) {
-               DRM_ERROR("Couldn't find encoder's connector\n");
-               return -ENOENT;
-       }
+       if (!connector)
+               return -EINVAL;
 
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
@@ -563,8 +537,8 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
                return err;
        }
 
-       if (dig && dig->afmt &&
-               radeon_encoder->audio && radeon_encoder->audio->set_avi_packet)
+       if (dig && dig->afmt && radeon_encoder->audio &&
+           radeon_encoder->audio->set_avi_packet)
                radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
                        buffer, sizeof(buffer));
 
@@ -722,30 +696,41 @@ static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
        if (!dig || !dig->afmt)
                return;
 
-       radeon_audio_set_mute(encoder, true);
+       if (!connector)
+               return;
 
-       radeon_audio_write_speaker_allocation(encoder);
-       radeon_audio_write_sad_regs(encoder);
-       radeon_audio_write_latency_fields(encoder, mode);
-       radeon_audio_set_dto(encoder, mode->clock);
-       radeon_audio_set_vbi_packet(encoder);
-       radeon_hdmi_set_color_depth(encoder);
-       radeon_audio_update_acr(encoder, mode->clock);
-       radeon_audio_set_audio_packet(encoder);
-       radeon_audio_select_pin(encoder);
+       if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+               radeon_audio_set_mute(encoder, true);
 
-       if (radeon_audio_set_avi_packet(encoder, mode) < 0)
-               return;
+               radeon_audio_write_speaker_allocation(encoder);
+               radeon_audio_write_sad_regs(encoder);
+               radeon_audio_write_latency_fields(encoder, mode);
+               radeon_audio_set_dto(encoder, mode->clock);
+               radeon_audio_set_vbi_packet(encoder);
+               radeon_hdmi_set_color_depth(encoder);
+               radeon_audio_update_acr(encoder, mode->clock);
+               radeon_audio_set_audio_packet(encoder);
+               radeon_audio_select_pin(encoder);
+
+               if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+                       return;
 
-       radeon_audio_set_mute(encoder, false);
+               radeon_audio_set_mute(encoder, false);
+       } else {
+               radeon_hdmi_set_color_depth(encoder);
+
+               if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+                       return;
+       }
 }
 
 static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                                    struct drm_display_mode *mode)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -759,22 +744,27 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
        if (!dig || !dig->afmt)
                return;
 
-       radeon_audio_write_speaker_allocation(encoder);
-       radeon_audio_write_sad_regs(encoder);
-       radeon_audio_write_latency_fields(encoder, mode);
-       if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev))
-               radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
-       else
-               radeon_audio_set_dto(encoder, dig_connector->dp_clock);
-       radeon_audio_set_audio_packet(encoder);
-       radeon_audio_select_pin(encoder);
-
-       if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+       if (!connector)
                return;
+
+       if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+               radeon_audio_write_speaker_allocation(encoder);
+               radeon_audio_write_sad_regs(encoder);
+               radeon_audio_write_latency_fields(encoder, mode);
+               if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev))
+                       radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+               else
+                       radeon_audio_set_dto(encoder, dig_connector->dp_clock);
+               radeon_audio_set_audio_packet(encoder);
+               radeon_audio_select_pin(encoder);
+
+               if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+                       return;
+       }
 }
 
 void radeon_audio_mode_set(struct drm_encoder *encoder,
-       struct drm_display_mode *mode)
+                          struct drm_display_mode *mode)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 
index 8438304f7139549c9ab785ec3f1decd50ac3254a..059cc3012062a7b50708620c557771dcfea821c0 100644 (file)
@@ -68,7 +68,8 @@ struct radeon_audio_funcs
 
 int radeon_audio_init(struct radeon_device *rdev);
 void radeon_audio_detect(struct drm_connector *connector,
-       enum drm_connector_status status);
+                        struct drm_encoder *encoder,
+                        enum drm_connector_status status);
 u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev,
        u32 offset, u32 reg);
 void radeon_audio_endpoint_wreg(struct radeon_device *rdev,
index 3e5f6b71f3adad72b0aae490ede2ae1f426c9ff5..c097d3a82bda734888ca46d05c14794738163642 100644 (file)
@@ -1255,10 +1255,15 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
 
                        if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) &&
                            (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) {
+                               u32 hss = (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8;
+
+                               if (hss > lvds->native_mode.hdisplay)
+                                       hss = (10 - 1) * 8;
+
                                lvds->native_mode.htotal = lvds->native_mode.hdisplay +
                                        (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8;
                                lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
-                                       (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8;
+                                       hss;
                                lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
                                        (RBIOS8(tmp + 23) * 8);
 
index cebb65e07e1d13f0bee01ee753f4c8a76e0e22d5..94b21ae70ef725781c8dc7d0ec8a30fbd48f0e0e 100644 (file)
@@ -1379,8 +1379,16 @@ out:
        /* updated in get modes as well since we need to know if it's analog or digital */
        radeon_connector_update_scratch_regs(connector, ret);
 
-       if (radeon_audio != 0)
-               radeon_audio_detect(connector, ret);
+       if ((radeon_audio != 0) && radeon_connector->use_digital) {
+               const struct drm_connector_helper_funcs *connector_funcs =
+                       connector->helper_private;
+
+               encoder = connector_funcs->best_encoder(connector);
+               if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) {
+                       radeon_connector_get_edid(connector);
+                       radeon_audio_detect(connector, encoder, ret);
+               }
+       }
 
 exit:
        pm_runtime_mark_last_busy(connector->dev->dev);
@@ -1717,8 +1725,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
 
        radeon_connector_update_scratch_regs(connector, ret);
 
-       if (radeon_audio != 0)
-               radeon_audio_detect(connector, ret);
+       if ((radeon_audio != 0) && encoder) {
+               radeon_connector_get_edid(connector);
+               radeon_audio_detect(connector, encoder, ret);
+       }
 
 out:
        pm_runtime_mark_last_busy(connector->dev->dev);
index 45e54060ee97eea33cd005b993c6ca704cf80a16..afaf346bd50e7c7628674e29d0eea14c8403e3ec 100644 (file)
@@ -91,15 +91,34 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
        struct radeon_device *rdev = crtc->dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev)) {
+               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+                      upper_32_bits(radeon_crtc->cursor_addr));
+               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+                      lower_32_bits(radeon_crtc->cursor_addr));
                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
                       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
                       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
        } else if (ASIC_IS_AVIVO(rdev)) {
+               if (rdev->family >= CHIP_RV770) {
+                       if (radeon_crtc->crtc_id)
+                               WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
+                                      upper_32_bits(radeon_crtc->cursor_addr));
+                       else
+                               WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
+                                      upper_32_bits(radeon_crtc->cursor_addr));
+               }
+
+               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+                      lower_32_bits(radeon_crtc->cursor_addr));
                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
                       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
        } else {
+               /* offset is from DISP(2)_BASE_ADDRESS */
+               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
+                      radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
+
                switch (radeon_crtc->crtc_id) {
                case 0:
                        WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
@@ -205,8 +224,9 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
                        | (x << 16)
                        | y));
                /* offset is from DISP(2)_BASE_ADDRESS */
-               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
-                                                                     (yorigin * 256)));
+               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
+                      radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
+                      yorigin * 256);
        }
 
        radeon_crtc->cursor_x = x;
@@ -227,53 +247,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
        return ret;
 }
 
-static int radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj)
-{
-       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-       struct radeon_device *rdev = crtc->dev->dev_private;
-       struct radeon_bo *robj = gem_to_radeon_bo(obj);
-       uint64_t gpu_addr;
-       int ret;
-
-       ret = radeon_bo_reserve(robj, false);
-       if (unlikely(ret != 0))
-               goto fail;
-       /* Only 27 bit offset for legacy cursor */
-       ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
-                                      ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
-                                      &gpu_addr);
-       radeon_bo_unreserve(robj);
-       if (ret)
-               goto fail;
-
-       if (ASIC_IS_DCE4(rdev)) {
-               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
-                      upper_32_bits(gpu_addr));
-               WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
-                      gpu_addr & 0xffffffff);
-       } else if (ASIC_IS_AVIVO(rdev)) {
-               if (rdev->family >= CHIP_RV770) {
-                       if (radeon_crtc->crtc_id)
-                               WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
-                       else
-                               WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
-               }
-               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
-                      gpu_addr & 0xffffffff);
-       } else {
-               radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
-               /* offset is from DISP(2)_BASE_ADDRESS */
-               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
-       }
-
-       return 0;
-
-fail:
-       drm_gem_object_unreference_unlocked(obj);
-
-       return ret;
-}
-
 int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
                            struct drm_file *file_priv,
                            uint32_t handle,
@@ -283,7 +256,9 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
                            int32_t hot_y)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
        struct drm_gem_object *obj;
+       struct radeon_bo *robj;
        int ret;
 
        if (!handle) {
@@ -305,6 +280,23 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
                return -ENOENT;
        }
 
+       robj = gem_to_radeon_bo(obj);
+       ret = radeon_bo_reserve(robj, false);
+       if (ret != 0) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+       /* Only 27 bit offset for legacy cursor */
+       ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
+                                      ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
+                                      &radeon_crtc->cursor_addr);
+       radeon_bo_unreserve(robj);
+       if (ret) {
+               DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
+               drm_gem_object_unreference_unlocked(obj);
+               return ret;
+       }
+
        radeon_crtc->cursor_width = width;
        radeon_crtc->cursor_height = height;
 
@@ -323,13 +315,7 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
                radeon_crtc->cursor_hot_y = hot_y;
        }
 
-       ret = radeon_set_cursor(crtc, obj);
-
-       if (ret)
-               DRM_ERROR("radeon_set_cursor returned %d, not changing cursor\n",
-                         ret);
-       else
-               radeon_show_cursor(crtc);
+       radeon_show_cursor(crtc);
 
        radeon_lock_cursor(crtc, false);
 
@@ -341,8 +327,7 @@ unpin:
                        radeon_bo_unpin(robj);
                        radeon_bo_unreserve(robj);
                }
-               if (radeon_crtc->cursor_bo != obj)
-                       drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
+               drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
        }
 
        radeon_crtc->cursor_bo = obj;
@@ -360,7 +345,6 @@ unpin:
 void radeon_cursor_reset(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-       int ret;
 
        if (radeon_crtc->cursor_bo) {
                radeon_lock_cursor(crtc, true);
@@ -368,12 +352,7 @@ void radeon_cursor_reset(struct drm_crtc *crtc)
                radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
                                          radeon_crtc->cursor_y);
 
-               ret = radeon_set_cursor(crtc, radeon_crtc->cursor_bo);
-               if (ret)
-                       DRM_ERROR("radeon_set_cursor returned %d, not showing "
-                                 "cursor\n", ret);
-               else
-                       radeon_show_cursor(crtc);
+               radeon_show_cursor(crtc);
 
                radeon_lock_cursor(crtc, false);
        }
index 2593b1168bd6ff09a8dbfa966e75d7445478be70..d8319dae8358846cfc4b8121e7786dbd8c6d17fa 100644 (file)
@@ -1079,6 +1079,22 @@ static bool radeon_check_pot_argument(int arg)
        return (arg & (arg - 1)) == 0;
 }
 
+/**
+ * Determine a sensible default GART size according to ASIC family.
+ *
+ * @family ASIC family name
+ */
+static int radeon_gart_size_auto(enum radeon_family family)
+{
+       /* default to a larger gart size on newer asics */
+       if (family >= CHIP_TAHITI)
+               return 2048;
+       else if (family >= CHIP_RV770)
+               return 1024;
+       else
+               return 512;
+}
+
 /**
  * radeon_check_arguments - validate module params
  *
@@ -1097,27 +1113,17 @@ static void radeon_check_arguments(struct radeon_device *rdev)
        }
 
        if (radeon_gart_size == -1) {
-               /* default to a larger gart size on newer asics */
-               if (rdev->family >= CHIP_RV770)
-                       radeon_gart_size = 1024;
-               else
-                       radeon_gart_size = 512;
+               radeon_gart_size = radeon_gart_size_auto(rdev->family);
        }
        /* gtt size must be power of two and greater or equal to 32M */
        if (radeon_gart_size < 32) {
                dev_warn(rdev->dev, "gart size (%d) too small\n",
                                radeon_gart_size);
-               if (rdev->family >= CHIP_RV770)
-                       radeon_gart_size = 1024;
-               else
-                       radeon_gart_size = 512;
+               radeon_gart_size = radeon_gart_size_auto(rdev->family);
        } else if (!radeon_check_pot_argument(radeon_gart_size)) {
                dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n",
                                radeon_gart_size);
-               if (rdev->family >= CHIP_RV770)
-                       radeon_gart_size = 1024;
-               else
-                       radeon_gart_size = 512;
+               radeon_gart_size = radeon_gart_size_auto(rdev->family);
        }
        rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20;
 
@@ -1572,11 +1578,21 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
                drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
        }
 
-       /* unpin the front buffers */
+       /* unpin the front buffers and cursors */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
                struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb);
                struct radeon_bo *robj;
 
+               if (radeon_crtc->cursor_bo) {
+                       struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
+                       r = radeon_bo_reserve(robj, false);
+                       if (r == 0) {
+                               radeon_bo_unpin(robj);
+                               radeon_bo_unreserve(robj);
+                       }
+               }
+
                if (rfb == NULL || rfb->obj == NULL) {
                        continue;
                }
@@ -1639,6 +1655,7 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
 {
        struct drm_connector *connector;
        struct radeon_device *rdev = dev->dev_private;
+       struct drm_crtc *crtc;
        int r;
 
        if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
@@ -1678,6 +1695,27 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
 
        radeon_restore_bios_scratch_regs(rdev);
 
+       /* pin cursors */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+               if (radeon_crtc->cursor_bo) {
+                       struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
+                       r = radeon_bo_reserve(robj, false);
+                       if (r == 0) {
+                               /* Only 27 bit offset for legacy cursor */
+                               r = radeon_bo_pin_restricted(robj,
+                                                            RADEON_GEM_DOMAIN_VRAM,
+                                                            ASIC_IS_AVIVO(rdev) ?
+                                                            0 : 1 << 27,
+                                                            &radeon_crtc->cursor_addr);
+                               if (r != 0)
+                                       DRM_ERROR("Failed to pin cursor BO (%d)\n", r);
+                               radeon_bo_unreserve(robj);
+                       }
+               }
+       }
+
        /* init dig PHYs, disp eng pll */
        if (rdev->is_atom_bios) {
                radeon_atom_encoder_init(rdev);
index 634793ea841889847ac090c32470548a1cae418d..aeb676708e60cfb1871326bfc5a689631bb98741 100644 (file)
@@ -257,6 +257,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
        }
 
        info->par = rfbdev;
+       info->skip_vt_switch = true;
 
        ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
        if (ret) {
index 5450fa95a47efdcde9aa664c740cbe578e4f5b26..c4777c8d0312a047790bcd309ac00fba2c8a02a4 100644 (file)
@@ -260,8 +260,10 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
                        }
                }
        }
-       mb();
-       radeon_gart_tlb_flush(rdev);
+       if (rdev->gart.ptr) {
+               mb();
+               radeon_gart_tlb_flush(rdev);
+       }
 }
 
 /**
@@ -306,8 +308,10 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
                        page_base += RADEON_GPU_PAGE_SIZE;
                }
        }
-       mb();
-       radeon_gart_tlb_flush(rdev);
+       if (rdev->gart.ptr) {
+               mb();
+               radeon_gart_tlb_flush(rdev);
+       }
        return 0;
 }
 
index ac3c1310b953182acb0db6db41add071fd88e737..3dcc5733ff6915b2e2497ca3d4ff800455f49c20 100644 (file)
@@ -36,6 +36,7 @@ void radeon_gem_object_free(struct drm_gem_object *gobj)
        if (robj) {
                if (robj->gem_base.import_attach)
                        drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
+               radeon_mn_unregister(robj);
                radeon_bo_unref(&robj);
        }
 }
@@ -428,7 +429,6 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
 int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
-       struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_gem_busy *args = data;
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
@@ -440,10 +440,16 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
                return -ENOENT;
        }
        robj = gem_to_radeon_bo(gobj);
-       r = radeon_bo_wait(robj, &cur_placement, true);
+
+       r = reservation_object_test_signaled_rcu(robj->tbo.resv, true);
+       if (r == 0)
+               r = -EBUSY;
+       else
+               r = 0;
+
+       cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type);
        args->domain = radeon_mem_type_to_domain(cur_placement);
        drm_gem_object_unreference_unlocked(gobj);
-       r = radeon_gem_handle_lockup(rdev, r);
        return r;
 }
 
@@ -471,6 +477,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
                r = ret;
 
        /* Flush HDP cache via MMIO if necessary */
+       cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type);
        if (rdev->asic->mmio_hdp_flush &&
            radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM)
                robj->rdev->asic->mmio_hdp_flush(rdev);
index 1162bfa464f3036192854f4d0f3f363eb1ee8cff..171d3e43c30cc02257df75645c6c77f0a726de33 100644 (file)
@@ -79,6 +79,11 @@ static void radeon_hotplug_work_func(struct work_struct *work)
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
 
+       /* we can race here at startup, some boards seem to trigger
+        * hotplug irqs when they shouldn't. */
+       if (!rdev->mode_info.mode_config_initialized)
+               return;
+
        mutex_lock(&mode_config->mutex);
        if (mode_config->num_connector) {
                list_for_each_entry(connector, &mode_config->connector_list, head)
index 6de5459316b53c60b41449c833b15dab31c0b45a..aecc3e3dec0ca093441e3871df414627b51e92ec 100644 (file)
@@ -237,7 +237,6 @@ struct radeon_afmt {
        int offset;
        bool last_buffer_filled_status;
        int id;
-       struct r600_audio_pin *pin;
 };
 
 struct radeon_mode_info {
@@ -343,7 +342,6 @@ struct radeon_crtc {
        int max_cursor_width;
        int max_cursor_height;
        uint32_t legacy_display_base_addr;
-       uint32_t legacy_cursor_offset;
        enum radeon_rmx_type rmx_type;
        u8 h_border;
        u8 v_border;
@@ -440,6 +438,7 @@ struct radeon_encoder_atom_dig {
        uint8_t backlight_level;
        int panel_mode;
        struct radeon_afmt *afmt;
+       struct r600_audio_pin *pin;
        int active_mst_links;
 };
 
index 318165d4855c4bf3aa9e4a23bddc38cc25481968..676362769b8dbfc9dea20e8c76c02e4208950b29 100644 (file)
@@ -75,7 +75,6 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
        bo = container_of(tbo, struct radeon_bo, tbo);
 
        radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1);
-       radeon_mn_unregister(bo);
 
        mutex_lock(&bo->rdev->gem.mutex);
        list_del_init(&bo->list);
index ec10533a49b87a905aa82eda96e48bddae32d87f..48d97c040f495cc69c0d890b5a5e6b4fee587a62 100644 (file)
@@ -493,38 +493,35 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
        }
 
        if (bo_va->it.start || bo_va->it.last) {
-               spin_lock(&vm->status_lock);
-               if (list_empty(&bo_va->vm_status)) {
-                       /* add a clone of the bo_va to clear the old address */
-                       struct radeon_bo_va *tmp;
-                       spin_unlock(&vm->status_lock);
-                       tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
-                       if (!tmp) {
-                               mutex_unlock(&vm->mutex);
-                               r = -ENOMEM;
-                               goto error_unreserve;
-                       }
-                       tmp->it.start = bo_va->it.start;
-                       tmp->it.last = bo_va->it.last;
-                       tmp->vm = vm;
-                       tmp->bo = radeon_bo_ref(bo_va->bo);
-                       spin_lock(&vm->status_lock);
-                       list_add(&tmp->vm_status, &vm->freed);
+               /* add a clone of the bo_va to clear the old address */
+               struct radeon_bo_va *tmp;
+               tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
+               if (!tmp) {
+                       mutex_unlock(&vm->mutex);
+                       r = -ENOMEM;
+                       goto error_unreserve;
                }
-               spin_unlock(&vm->status_lock);
+               tmp->it.start = bo_va->it.start;
+               tmp->it.last = bo_va->it.last;
+               tmp->vm = vm;
+               tmp->bo = radeon_bo_ref(bo_va->bo);
 
                interval_tree_remove(&bo_va->it, &vm->va);
+               spin_lock(&vm->status_lock);
                bo_va->it.start = 0;
                bo_va->it.last = 0;
+               list_del_init(&bo_va->vm_status);
+               list_add(&tmp->vm_status, &vm->freed);
+               spin_unlock(&vm->status_lock);
        }
 
        if (soffset || eoffset) {
+               spin_lock(&vm->status_lock);
                bo_va->it.start = soffset;
                bo_va->it.last = eoffset - 1;
-               interval_tree_insert(&bo_va->it, &vm->va);
-               spin_lock(&vm->status_lock);
                list_add(&bo_va->vm_status, &vm->cleared);
                spin_unlock(&vm->status_lock);
+               interval_tree_insert(&bo_va->it, &vm->va);
        }
 
        bo_va->flags = flags;
@@ -1158,7 +1155,8 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
 
        list_for_each_entry(bo_va, &bo->va, bo_list) {
                spin_lock(&bo_va->vm->status_lock);
-               if (list_empty(&bo_va->vm_status))
+               if (list_empty(&bo_va->vm_status) &&
+                   (bo_va->it.start || bo_va->it.last))
                        list_add(&bo_va->vm_status, &bo_va->vm->invalidated);
                spin_unlock(&bo_va->vm->status_lock);
        }
index 26388b5dd6edd1dd50c7d0fd947280f00cf3b19d..07037e32dea327f935ef39e0bdafea8fb640b39a 100644 (file)
@@ -6466,23 +6466,27 @@ restart_ih:
                case 1: /* D1 vblank/vline */
                        switch (src_data) {
                        case 0: /* D1 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[0]) {
-                                               drm_handle_vblank(rdev->ddev, 0);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[0]))
-                                               radeon_crtc_handle_vblank(rdev, 0);
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[0]) {
+                                       drm_handle_vblank(rdev->ddev, 0);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[0]))
+                                       radeon_crtc_handle_vblank(rdev, 0);
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vblank\n");
+
                                break;
                        case 1: /* D1 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D1 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D1 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -6492,23 +6496,27 @@ restart_ih:
                case 2: /* D2 vblank/vline */
                        switch (src_data) {
                        case 0: /* D2 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[1]) {
-                                               drm_handle_vblank(rdev->ddev, 1);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[1]))
-                                               radeon_crtc_handle_vblank(rdev, 1);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[1]) {
+                                       drm_handle_vblank(rdev->ddev, 1);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[1]))
+                                       radeon_crtc_handle_vblank(rdev, 1);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vblank\n");
+
                                break;
                        case 1: /* D2 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D2 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D2 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -6518,23 +6526,27 @@ restart_ih:
                case 3: /* D3 vblank/vline */
                        switch (src_data) {
                        case 0: /* D3 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[2]) {
-                                               drm_handle_vblank(rdev->ddev, 2);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[2]))
-                                               radeon_crtc_handle_vblank(rdev, 2);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D3 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[2]) {
+                                       drm_handle_vblank(rdev->ddev, 2);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[2]))
+                                       radeon_crtc_handle_vblank(rdev, 2);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D3 vblank\n");
+
                                break;
                        case 1: /* D3 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D3 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D3 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -6544,23 +6556,27 @@ restart_ih:
                case 4: /* D4 vblank/vline */
                        switch (src_data) {
                        case 0: /* D4 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[3]) {
-                                               drm_handle_vblank(rdev->ddev, 3);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[3]))
-                                               radeon_crtc_handle_vblank(rdev, 3);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D4 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[3]) {
+                                       drm_handle_vblank(rdev->ddev, 3);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[3]))
+                                       radeon_crtc_handle_vblank(rdev, 3);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D4 vblank\n");
+
                                break;
                        case 1: /* D4 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D4 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D4 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -6570,23 +6586,27 @@ restart_ih:
                case 5: /* D5 vblank/vline */
                        switch (src_data) {
                        case 0: /* D5 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[4]) {
-                                               drm_handle_vblank(rdev->ddev, 4);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[4]))
-                                               radeon_crtc_handle_vblank(rdev, 4);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D5 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[4]) {
+                                       drm_handle_vblank(rdev->ddev, 4);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[4]))
+                                       radeon_crtc_handle_vblank(rdev, 4);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D5 vblank\n");
+
                                break;
                        case 1: /* D5 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D5 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D5 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -6596,23 +6616,27 @@ restart_ih:
                case 6: /* D6 vblank/vline */
                        switch (src_data) {
                        case 0: /* D6 vblank */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
-                                       if (rdev->irq.crtc_vblank_int[5]) {
-                                               drm_handle_vblank(rdev->ddev, 5);
-                                               rdev->pm.vblank_sync = true;
-                                               wake_up(&rdev->irq.vblank_queue);
-                                       }
-                                       if (atomic_read(&rdev->irq.pflip[5]))
-                                               radeon_crtc_handle_vblank(rdev, 5);
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
-                                       DRM_DEBUG("IH: D6 vblank\n");
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               if (rdev->irq.crtc_vblank_int[5]) {
+                                       drm_handle_vblank(rdev->ddev, 5);
+                                       rdev->pm.vblank_sync = true;
+                                       wake_up(&rdev->irq.vblank_queue);
                                }
+                               if (atomic_read(&rdev->irq.pflip[5]))
+                                       radeon_crtc_handle_vblank(rdev, 5);
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+                               DRM_DEBUG("IH: D6 vblank\n");
+
                                break;
                        case 1: /* D6 vline */
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
-                                       DRM_DEBUG("IH: D6 vline\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+                               DRM_DEBUG("IH: D6 vline\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
@@ -6632,88 +6656,112 @@ restart_ih:
                case 42: /* HPD hotplug */
                        switch (src_data) {
                        case 0:
-                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD1\n");
+
                                break;
                        case 1:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD2\n");
+
                                break;
                        case 2:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD3\n");
+
                                break;
                        case 3:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD4\n");
+
                                break;
                        case 4:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD5\n");
+
                                break;
                        case 5:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
-                                       queue_hotplug = true;
-                                       DRM_DEBUG("IH: HPD6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+                               queue_hotplug = true;
+                               DRM_DEBUG("IH: HPD6\n");
+
                                break;
                        case 6:
-                               if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 1\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 1\n");
+
                                break;
                        case 7:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 2\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 2\n");
+
                                break;
                        case 8:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 3\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 3\n");
+
                                break;
                        case 9:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 4\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 4\n");
+
                                break;
                        case 10:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 5\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 5\n");
+
                                break;
                        case 11:
-                               if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
-                                       rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
-                                       queue_dp = true;
-                                       DRM_DEBUG("IH: HPD_RX 6\n");
-                               }
+                               if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT))
+                                       DRM_DEBUG("IH: IH event w/o asserted irq bit?\n");
+
+                               rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT;
+                               queue_dp = true;
+                               DRM_DEBUG("IH: HPD_RX 6\n");
+
                                break;
                        default:
                                DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
index 1dbdf3230daed2b4c829e3ed5b9800a007691fea..787cd8fd897faf52e5874cb0183a07bc36594fdc 100644 (file)
@@ -2926,6 +2926,7 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = {
        /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
        { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
        { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
+       { PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
        { 0, 0, 0, 0 },
 };
 
index 01b558fe369539f447d36493f3bcd7e1bc4f3ded..9a0c2911272a9062a65f10096928e73edd35dd4f 100644 (file)
@@ -555,7 +555,6 @@ static struct platform_driver rockchip_drm_platform_driver = {
        .probe = rockchip_drm_platform_probe,
        .remove = rockchip_drm_platform_remove,
        .driver = {
-               .owner = THIS_MODULE,
                .name = "rockchip-drm",
                .of_match_table = rockchip_drm_dt_ids,
                .pm = &rockchip_drm_pm_ops,
index 77d52893d40f6086082887d22c3530a7de6b9048..002645bb5bbf9b83f30c0f383050c817d8e43dbc 100644 (file)
@@ -162,7 +162,8 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev)
        struct rockchip_drm_private *private = dev->dev_private;
        struct drm_fb_helper *fb_helper = &private->fbdev_helper;
 
-       drm_fb_helper_hotplug_event(fb_helper);
+       if (fb_helper)
+               drm_fb_helper_hotplug_event(fb_helper);
 }
 
 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
index eb2282cc4a56507819a5ab638af504499157157a..eba5f8a52fbd9ff2bf7941687f54e11320cb10b3 100644 (file)
@@ -54,55 +54,56 @@ static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
                       &rk_obj->dma_attrs);
 }
 
-int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
-                         struct vm_area_struct *vma)
+static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
+                                       struct vm_area_struct *vma)
+
 {
+       int ret;
        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
        struct drm_device *drm = obj->dev;
-       unsigned long vm_size;
 
-       vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
-       vm_size = vma->vm_end - vma->vm_start;
-
-       if (vm_size > obj->size)
-               return -EINVAL;
+       /*
+        * dma_alloc_attrs() allocated a struct page table for rk_obj, so clear
+        * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
+        */
+       vma->vm_flags &= ~VM_PFNMAP;
 
-       return dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
+       ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
                             obj->size, &rk_obj->dma_attrs);
+       if (ret)
+               drm_gem_vm_close(vma);
+
+       return ret;
 }
 
-/* drm driver mmap file operations */
-int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
+                         struct vm_area_struct *vma)
 {
-       struct drm_file *priv = filp->private_data;
-       struct drm_device *dev = priv->minor->dev;
-       struct drm_gem_object *obj;
-       struct drm_vma_offset_node *node;
+       struct drm_device *drm = obj->dev;
        int ret;
 
-       if (drm_device_is_unplugged(dev))
-               return -ENODEV;
+       mutex_lock(&drm->struct_mutex);
+       ret = drm_gem_mmap_obj(obj, obj->size, vma);
+       mutex_unlock(&drm->struct_mutex);
+       if (ret)
+               return ret;
 
-       mutex_lock(&dev->struct_mutex);
+       return rockchip_drm_gem_object_mmap(obj, vma);
+}
 
-       node = drm_vma_offset_exact_lookup(dev->vma_offset_manager,
-                                          vma->vm_pgoff,
-                                          vma_pages(vma));
-       if (!node) {
-               mutex_unlock(&dev->struct_mutex);
-               DRM_ERROR("failed to find vma node.\n");
-               return -EINVAL;
-       } else if (!drm_vma_node_is_allowed(node, filp)) {
-               mutex_unlock(&dev->struct_mutex);
-               return -EACCES;
-       }
+/* drm driver mmap file operations */
+int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_gem_object *obj;
+       int ret;
 
-       obj = container_of(node, struct drm_gem_object, vma_node);
-       ret = rockchip_gem_mmap_buf(obj, vma);
+       ret = drm_gem_mmap(filp, vma);
+       if (ret)
+               return ret;
 
-       mutex_unlock(&dev->struct_mutex);
+       obj = vma->vm_private_data;
 
-       return ret;
+       return rockchip_drm_gem_object_mmap(obj, vma);
 }
 
 struct rockchip_gem_object *
index dc65161d7cad20acb2f079bdb6b229cf779b3613..34b78e73653248316fcd24732d03d253454c6e50 100644 (file)
@@ -170,6 +170,7 @@ struct vop_win_phy {
 
        struct vop_reg enable;
        struct vop_reg format;
+       struct vop_reg rb_swap;
        struct vop_reg act_info;
        struct vop_reg dsp_info;
        struct vop_reg dsp_st;
@@ -199,8 +200,12 @@ struct vop_data {
 static const uint32_t formats_01[] = {
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_ABGR8888,
        DRM_FORMAT_RGB888,
+       DRM_FORMAT_BGR888,
        DRM_FORMAT_RGB565,
+       DRM_FORMAT_BGR565,
        DRM_FORMAT_NV12,
        DRM_FORMAT_NV16,
        DRM_FORMAT_NV24,
@@ -209,8 +214,12 @@ static const uint32_t formats_01[] = {
 static const uint32_t formats_234[] = {
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_ABGR8888,
        DRM_FORMAT_RGB888,
+       DRM_FORMAT_BGR888,
        DRM_FORMAT_RGB565,
+       DRM_FORMAT_BGR565,
 };
 
 static const struct vop_win_phy win01_data = {
@@ -218,6 +227,7 @@ static const struct vop_win_phy win01_data = {
        .nformats = ARRAY_SIZE(formats_01),
        .enable = VOP_REG(WIN0_CTRL0, 0x1, 0),
        .format = VOP_REG(WIN0_CTRL0, 0x7, 1),
+       .rb_swap = VOP_REG(WIN0_CTRL0, 0x1, 12),
        .act_info = VOP_REG(WIN0_ACT_INFO, 0x1fff1fff, 0),
        .dsp_info = VOP_REG(WIN0_DSP_INFO, 0x0fff0fff, 0),
        .dsp_st = VOP_REG(WIN0_DSP_ST, 0x1fff1fff, 0),
@@ -234,6 +244,7 @@ static const struct vop_win_phy win23_data = {
        .nformats = ARRAY_SIZE(formats_234),
        .enable = VOP_REG(WIN2_CTRL0, 0x1, 0),
        .format = VOP_REG(WIN2_CTRL0, 0x7, 1),
+       .rb_swap = VOP_REG(WIN2_CTRL0, 0x1, 12),
        .dsp_info = VOP_REG(WIN2_DSP_INFO0, 0x0fff0fff, 0),
        .dsp_st = VOP_REG(WIN2_DSP_ST0, 0x1fff1fff, 0),
        .yrgb_mst = VOP_REG(WIN2_MST0, 0xffffffff, 0),
@@ -242,15 +253,6 @@ static const struct vop_win_phy win23_data = {
        .dst_alpha_ctl = VOP_REG(WIN2_DST_ALPHA_CTRL, 0xff, 0),
 };
 
-static const struct vop_win_phy cursor_data = {
-       .data_formats = formats_234,
-       .nformats = ARRAY_SIZE(formats_234),
-       .enable = VOP_REG(HWC_CTRL0, 0x1, 0),
-       .format = VOP_REG(HWC_CTRL0, 0x7, 1),
-       .dsp_st = VOP_REG(HWC_DSP_ST, 0x1fff1fff, 0),
-       .yrgb_mst = VOP_REG(HWC_MST, 0xffffffff, 0),
-};
-
 static const struct vop_ctrl ctrl_data = {
        .standby = VOP_REG(SYS_CTRL, 0x1, 22),
        .gate_en = VOP_REG(SYS_CTRL, 0x1, 23),
@@ -282,14 +284,14 @@ static const struct vop_reg_data vop_init_reg_table[] = {
 /*
  * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
  * special support to get alpha blending working.  For now, just use overlay
- * window 1 for the drm cursor.
+ * window 3 for the drm cursor.
+ *
  */
 static const struct vop_win_data rk3288_vop_win_data[] = {
        { .base = 0x00, .phy = &win01_data, .type = DRM_PLANE_TYPE_PRIMARY },
-       { .base = 0x40, .phy = &win01_data, .type = DRM_PLANE_TYPE_CURSOR },
+       { .base = 0x40, .phy = &win01_data, .type = DRM_PLANE_TYPE_OVERLAY },
        { .base = 0x00, .phy = &win23_data, .type = DRM_PLANE_TYPE_OVERLAY },
-       { .base = 0x50, .phy = &win23_data, .type = DRM_PLANE_TYPE_OVERLAY },
-       { .base = 0x00, .phy = &cursor_data, .type = DRM_PLANE_TYPE_OVERLAY },
+       { .base = 0x50, .phy = &win23_data, .type = DRM_PLANE_TYPE_CURSOR },
 };
 
 static const struct vop_data rk3288_vop = {
@@ -352,15 +354,32 @@ static inline void vop_mask_write_relaxed(struct vop *vop, uint32_t offset,
        }
 }
 
+static bool has_rb_swapped(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
+       case DRM_FORMAT_BGR888:
+       case DRM_FORMAT_BGR565:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static enum vop_data_format vop_convert_format(uint32_t format)
 {
        switch (format) {
        case DRM_FORMAT_XRGB8888:
        case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
                return VOP_FMT_ARGB8888;
        case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_BGR888:
                return VOP_FMT_RGB888;
        case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_BGR565:
                return VOP_FMT_RGB565;
        case DRM_FORMAT_NV12:
                return VOP_FMT_YUV420SP;
@@ -378,6 +397,7 @@ static bool is_alpha_support(uint32_t format)
 {
        switch (format) {
        case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_ABGR8888:
                return true;
        default:
                return false;
@@ -588,6 +608,7 @@ static int vop_update_plane_event(struct drm_plane *plane,
        enum vop_data_format format;
        uint32_t val;
        bool is_alpha;
+       bool rb_swap;
        bool visible;
        int ret;
        struct drm_rect dest = {
@@ -621,6 +642,7 @@ static int vop_update_plane_event(struct drm_plane *plane,
                return 0;
 
        is_alpha = is_alpha_support(fb->pixel_format);
+       rb_swap = has_rb_swapped(fb->pixel_format);
        format = vop_convert_format(fb->pixel_format);
        if (format < 0)
                return format;
@@ -689,6 +711,7 @@ static int vop_update_plane_event(struct drm_plane *plane,
        val = (dsp_sty - 1) << 16;
        val |= (dsp_stx - 1) & 0xffff;
        VOP_WIN_SET(vop, win, dsp_st, val);
+       VOP_WIN_SET(vop, win, rb_swap, rb_swap);
 
        if (is_alpha) {
                VOP_WIN_SET(vop, win, dst_alpha_ctl,
index 882cccdad27249c8e3afa992419fb0fb16bec97b..ac6fe40b99f753b267a5e78647c0bdb2e078c5bd 100644 (file)
@@ -490,7 +490,8 @@ pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp)
        else if (boot_cpu_data.x86 > 3)
                tmp = pgprot_noncached(tmp);
 #endif
-#if defined(__ia64__) || defined(__arm__) || defined(__powerpc__)
+#if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__powerpc__)
        if (caching_flags & TTM_PL_FLAG_WC)
                tmp = pgprot_writecombine(tmp);
        else
index 3077f1554099932f6f477841182fb4eb278c60ea..624d941aaad163f6b81ddff616f9fa868f1c28ea 100644 (file)
@@ -963,14 +963,13 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
        } else {
                pool->npages_free += count;
                list_splice(&ttm_dma->pages_list, &pool->free_list);
-               npages = count;
-               if (pool->npages_free > _manager->options.max_size) {
+               /*
+                * Wait to have at at least NUM_PAGES_TO_ALLOC number of pages
+                * to free in order to minimize calls to set_memory_wb().
+                */
+               if (pool->npages_free >= (_manager->options.max_size +
+                                         NUM_PAGES_TO_ALLOC))
                        npages = pool->npages_free - _manager->options.max_size;
-                       /* free at least NUM_PAGES_TO_ALLOC number of pages
-                        * to reduce calls to set_memory_wb */
-                       if (npages < NUM_PAGES_TO_ALLOC)
-                               npages = NUM_PAGES_TO_ALLOC;
-               }
        }
        spin_unlock_irqrestore(&pool->lock, irq_flags);
 
index 654c8daeb5ab3d0dd84a2ed1d32af633d6955ac9..97ad3bcb99a75a441a54150f779415dc59236ac7 100644 (file)
@@ -2492,7 +2492,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes,
                                     true, NULL);
        if (unlikely(ret != 0))
-               goto out_err;
+               goto out_err_nores;
 
        ret = vmw_validate_buffers(dev_priv, sw_context);
        if (unlikely(ret != 0))
@@ -2536,6 +2536,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        vmw_resource_relocations_free(&sw_context->res_relocations);
 
        vmw_fifo_commit(dev_priv, command_size);
+       mutex_unlock(&dev_priv->binding_mutex);
 
        vmw_query_bo_switch_commit(dev_priv, sw_context);
        ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
@@ -2551,7 +2552,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                DRM_ERROR("Fence submission error. Syncing.\n");
 
        vmw_resource_list_unreserve(&sw_context->resource_list, false);
-       mutex_unlock(&dev_priv->binding_mutex);
 
        ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
                                    (void *) fence);
index 6d2f39d36e445bda4840f06d7eb1f779081f2c22..00f2058944e55872ba25673744e648ea6bc0a12e 100644 (file)
@@ -1107,6 +1107,9 @@ static int ipu_irq_init(struct ipu_soc *ipu)
                return ret;
        }
 
+       for (i = 0; i < IPU_NUM_IRQS; i += 32)
+               ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
+
        for (i = 0; i < IPU_NUM_IRQS; i += 32) {
                gc = irq_get_domain_generic_chip(ipu->domain, i);
                gc->reg_base = ipu->cm_reg;
index f822fd2a1adabc4b3e53d86155c2d9e50d3d241e..884d82f9190e214636a539cb2db884a1d175c945 100644 (file)
@@ -546,6 +546,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index 157c627750535e8943769e3078de068e4f1c7a47..e6fce23b121adb662656bea26d8a4ace812afc9c 100644 (file)
@@ -1782,6 +1782,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -2463,6 +2466,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
index 3318de690e00666bf7da60c84189a1fc54a0a544..a2dbbbe0d8d7e81b06ac6d646737413fe4d1d357 100644 (file)
@@ -356,6 +356,8 @@ static int cp2112_read(struct cp2112_device *dev, u8 *data, size_t size)
        struct cp2112_force_read_report report;
        int ret;
 
+       if (size > sizeof(dev->read_data))
+               size = sizeof(dev->read_data);
        report.report = CP2112_DATA_READ_FORCE_SEND;
        report.length = cpu_to_be16(size);
 
index b04b0820d816323a01d147c702503b0797734ea4..b3b225b75d0ab7e497c389d0c9caa777da1f6948 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI   0x0272
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO            0x0273
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS            0x0274
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
 #define USB_DEVICE_ID_APPLE_IRCONTROL  0x8240
index 3511bbaba505a4524ad382297ec1e486e21e7e48..e3c63640df737d5527c6d2609622417a4e03c8d3 100644 (file)
@@ -462,12 +462,15 @@ out:
 
 static void hidinput_cleanup_battery(struct hid_device *dev)
 {
+       const struct power_supply_desc *psy_desc;
+
        if (!dev->battery)
                return;
 
+       psy_desc = dev->battery->desc;
        power_supply_unregister(dev->battery);
-       kfree(dev->battery->desc->name);
-       kfree(dev->battery->desc);
+       kfree(psy_desc->name);
+       kfree(psy_desc);
        dev->battery = NULL;
 }
 #else  /* !CONFIG_HID_BATTERY_STRENGTH */
index 6a9b05b328a9d40e06b09ed8f8c6e6010669374b..7c811252c1cefebb2418944a7f391117a8a92b6d 100644 (file)
@@ -778,9 +778,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        /*
         * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
         * for the stylus.
+        * The check for mt_report_id ensures we don't process
+        * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical
+        * collection, but within the report ID.
         */
        if (field->physical == HID_DG_STYLUS)
                return 0;
+       else if ((field->physical == 0) &&
+                (field->report->id != td->mt_report_id) &&
+                (td->mt_report_id != -1))
+               return 0;
 
        if (field->application == HID_DG_TOUCHSCREEN ||
            field->application == HID_DG_TOUCHPAD)
index 94167310e15a4c95001d339d4da3b7319f9005eb..b905d501e752d607b6fc1731ad89ff3d23ce7cd0 100644 (file)
@@ -858,7 +858,7 @@ static int uclogic_tablet_enable(struct hid_device *hdev)
        for (p = drvdata->rdesc;
             p <= drvdata->rdesc + drvdata->rsize - 4;) {
                if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
-                   p[3] < sizeof(params)) {
+                   p[3] < ARRAY_SIZE(params)) {
                        v = params[p[3]];
                        put_unaligned(cpu_to_le32(v), (s32 *)p);
                        p += 4;
index 53e7de7cb9e25e6861f1acb5e3438e590b2e70ad..20f9a653444c21d0ef89f4561d4d68544dff4bf0 100644 (file)
@@ -87,6 +87,9 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
index 4c0ffca97befd61cf3cdd947138d14070c4e7895..01b937e63cf37ec1424a1aad9eee0caef682c010 100644 (file)
@@ -1271,17 +1271,52 @@ fail_leds:
        pad_input_dev = NULL;
        wacom_wac->pad_registered = false;
 fail_register_pad_input:
-       input_unregister_device(touch_input_dev);
+       if (touch_input_dev)
+               input_unregister_device(touch_input_dev);
        wacom_wac->touch_input = NULL;
        wacom_wac->touch_registered = false;
 fail_register_touch_input:
-       input_unregister_device(pen_input_dev);
+       if (pen_input_dev)
+               input_unregister_device(pen_input_dev);
        wacom_wac->pen_input = NULL;
        wacom_wac->pen_registered = false;
 fail_register_pen_input:
        return error;
 }
 
+/*
+ * Not all devices report physical dimensions from HID.
+ * Compute the default from hardcoded logical dimension
+ * and resolution before driver overwrites them.
+ */
+static void wacom_set_default_phy(struct wacom_features *features)
+{
+       if (features->x_resolution) {
+               features->x_phy = (features->x_max * 100) /
+                                       features->x_resolution;
+               features->y_phy = (features->y_max * 100) /
+                                       features->y_resolution;
+       }
+}
+
+static void wacom_calculate_res(struct wacom_features *features)
+{
+       /* set unit to "100th of a mm" for devices not reported by HID */
+       if (!features->unit) {
+               features->unit = 0x11;
+               features->unitExpo = -3;
+       }
+
+       features->x_resolution = wacom_calc_hid_res(features->x_max,
+                                                   features->x_phy,
+                                                   features->unit,
+                                                   features->unitExpo);
+       features->y_resolution = wacom_calc_hid_res(features->y_max,
+                                                   features->y_phy,
+                                                   features->unit,
+                                                   features->unitExpo);
+}
+
 static void wacom_wireless_work(struct work_struct *work)
 {
        struct wacom *wacom = container_of(work, struct wacom, work);
@@ -1339,6 +1374,8 @@ static void wacom_wireless_work(struct work_struct *work)
                if (wacom_wac1->features.type != INTUOSHT &&
                    wacom_wac1->features.type != BAMBOO_PT)
                        wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
+               wacom_set_default_phy(&wacom_wac1->features);
+               wacom_calculate_res(&wacom_wac1->features);
                snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
                         wacom_wac1->features.name);
                snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
@@ -1357,7 +1394,9 @@ static void wacom_wireless_work(struct work_struct *work)
                        wacom_wac2->features =
                                *((struct wacom_features *)id->driver_data);
                        wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
+                       wacom_set_default_phy(&wacom_wac2->features);
                        wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
+                       wacom_calculate_res(&wacom_wac2->features);
                        snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
                                 "%s (WL) Finger",wacom_wac2->features.name);
                        snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
@@ -1405,39 +1444,6 @@ void wacom_battery_work(struct work_struct *work)
        }
 }
 
-/*
- * Not all devices report physical dimensions from HID.
- * Compute the default from hardcoded logical dimension
- * and resolution before driver overwrites them.
- */
-static void wacom_set_default_phy(struct wacom_features *features)
-{
-       if (features->x_resolution) {
-               features->x_phy = (features->x_max * 100) /
-                                       features->x_resolution;
-               features->y_phy = (features->y_max * 100) /
-                                       features->y_resolution;
-       }
-}
-
-static void wacom_calculate_res(struct wacom_features *features)
-{
-       /* set unit to "100th of a mm" for devices not reported by HID */
-       if (!features->unit) {
-               features->unit = 0x11;
-               features->unitExpo = -3;
-       }
-
-       features->x_resolution = wacom_calc_hid_res(features->x_max,
-                                                   features->x_phy,
-                                                   features->unit,
-                                                   features->unitExpo);
-       features->y_resolution = wacom_calc_hid_res(features->y_max,
-                                                   features->y_phy,
-                                                   features->unit,
-                                                   features->unitExpo);
-}
-
 static size_t wacom_compute_pktlen(struct hid_device *hdev)
 {
        struct hid_report_enum *report_enum;
index 232da89f4e886fe02b82d452c1a0868f0b65b967..0d244239e55def103f786254f3f617a84b2f0ba2 100644 (file)
@@ -2213,6 +2213,9 @@ void wacom_setup_device_quirks(struct wacom *wacom)
                        features->x_max = 4096;
                        features->y_max = 4096;
                }
+               else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) {
+                       features->device_type |= WACOM_DEVICETYPE_PAD;
+               }
        }
 
        /*
index 37c16afe007a0524eaacb5edcae9399bebfae897..c8487894b31236cefd761b24cac48fb4e17e6d52 100644 (file)
@@ -929,6 +929,21 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 
 MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
 
+static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = {
+       {
+               /*
+                * CPU fan speed going up and down on Dell Studio XPS 8100
+                * for unknown reasons.
+                */
+               .ident = "Dell Studio XPS 8100",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8100"),
+               },
+       },
+       { }
+};
+
 /*
  * Probe for the presence of a supported laptop.
  */
@@ -940,7 +955,8 @@ static int __init i8k_probe(void)
        /*
         * Get DMI information
         */
-       if (!dmi_check_system(i8k_dmi_table)) {
+       if (!dmi_check_system(i8k_dmi_table) ||
+           dmi_check_system(i8k_blacklist_dmi_table)) {
                if (!ignore_dmi && !force)
                        return -ENODEV;
 
index 9b55e673b67caf1365c7452ce51a22a37510af02..85d106fe3ce8628061901b53240e546a884cbea0 100644 (file)
@@ -582,6 +582,7 @@ static const struct of_device_id g762_dt_match[] = {
        { .compatible = "gmt,g763" },
        { },
 };
+MODULE_DEVICE_TABLE(of, g762_dt_match);
 
 /*
  * Grab clock (a required property), enable it, get (fixed) clock frequency
index 28fcb2e246d55a7acc52703e434b98de3e22c45b..fbfc02bb2cfa13c5bc22ece3a47a3cac1af07005 100644 (file)
@@ -195,7 +195,7 @@ abort:
 }
 
 static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index,
-                                unsigned int voltage)
+                                unsigned long voltage)
 {
        int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
        int err;
index b77b82f244800628843c103ae7dfcf157bd774ce..08ff89d222e5ff79a3c5cf37fa1b7729f70fe303 100644 (file)
@@ -412,8 +412,9 @@ static ssize_t show_pwm(struct device *dev,
        return sprintf(buf, "%d\n", val);
 }
 
-static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
-                         const char *buf, size_t count)
+static ssize_t store_enable(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
 {
        int index = to_sensor_dev_attr(devattr)->index;
        struct nct7904_data *data = dev_get_drvdata(dev);
@@ -422,18 +423,18 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
 
        if (kstrtoul(buf, 10, &val) < 0)
                return -EINVAL;
-       if (val > 1 || (val && !data->fan_mode[index]))
+       if (val < 1 || val > 2 || (val == 2 && !data->fan_mode[index]))
                return -EINVAL;
 
        ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + index,
-                               val ? data->fan_mode[index] : 0);
+                               val == 2 ? data->fan_mode[index] : 0);
 
        return ret ? ret : count;
 }
 
-/* Return 0 for manual mode or 1 for SmartFan mode */
-static ssize_t show_mode(struct device *dev,
-                        struct device_attribute *devattr, char *buf)
+/* Return 1 for manual mode or 2 for SmartFan mode */
+static ssize_t show_enable(struct device *dev,
+                          struct device_attribute *devattr, char *buf)
 {
        int index = to_sensor_dev_attr(devattr)->index;
        struct nct7904_data *data = dev_get_drvdata(dev);
@@ -443,36 +444,36 @@ static ssize_t show_mode(struct device *dev,
        if (val < 0)
                return val;
 
-       return sprintf(buf, "%d\n", val ? 1 : 0);
+       return sprintf(buf, "%d\n", val ? 2 : 1);
 }
 
 /* 2 attributes per channel: pwm and mode */
-static SENSOR_DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 0);
-static SENSOR_DEVICE_ATTR(fan1_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 0);
-static SENSOR_DEVICE_ATTR(fan2_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 1);
-static SENSOR_DEVICE_ATTR(fan2_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 1);
-static SENSOR_DEVICE_ATTR(fan3_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 2);
-static SENSOR_DEVICE_ATTR(fan3_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 2);
-static SENSOR_DEVICE_ATTR(fan4_pwm, S_IRUGO | S_IWUSR,
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR,
                        show_pwm, store_pwm, 3);
-static SENSOR_DEVICE_ATTR(fan4_mode, S_IRUGO | S_IWUSR,
-                       show_mode, store_mode, 3);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
+                       show_enable, store_enable, 3);
 
 static struct attribute *nct7904_fanctl_attrs[] = {
-       &sensor_dev_attr_fan1_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan1_mode.dev_attr.attr,
-       &sensor_dev_attr_fan2_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan2_mode.dev_attr.attr,
-       &sensor_dev_attr_fan3_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan3_mode.dev_attr.attr,
-       &sensor_dev_attr_fan4_pwm.dev_attr.attr,
-       &sensor_dev_attr_fan4_mode.dev_attr.attr,
+       &sensor_dev_attr_pwm1.dev_attr.attr,
+       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm2.dev_attr.attr,
+       &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm3.dev_attr.attr,
+       &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+       &sensor_dev_attr_pwm4.dev_attr.attr,
+       &sensor_dev_attr_pwm4_enable.dev_attr.attr,
        NULL
 };
 
@@ -574,6 +575,7 @@ static const struct i2c_device_id nct7904_id[] = {
        {"nct7904", 0},
        {}
 };
+MODULE_DEVICE_TABLE(i2c, nct7904_id);
 
 static struct i2c_driver nct7904_driver = {
        .class = I2C_CLASS_HWMON,
index 35ac23768ce9662fc513cdf8d0cad3f2f8447f4d..577d58d1f1a19881a23063cccf39cf5158d88520 100644 (file)
@@ -633,6 +633,7 @@ config I2C_MPC
 config I2C_MT65XX
        tristate "MediaTek I2C adapter"
        depends on ARCH_MEDIATEK || COMPILE_TEST
+       depends on HAS_DMA
        help
          This selects the MediaTek(R) Integrated Inter Circuit bus driver
          for MT65xx and MT81xx.
index af162b4c7a6d9b8b30756c53147eb3de458b3d5e..025686d4164058498216862d37af9ad114fe4fa2 100644 (file)
@@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, iface);
 
-       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, "
                "regs_base@%p\n", iface->regs_base);
 
        return 0;
@@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init);
 module_exit(i2c_bfin_twi_exit);
 
 MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
-MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:i2c-bfin-twi");
index 19b2d689a5ef72d76f2745bb3cb35dad78e61ad2..f325663c27c532645a1901a385ac6d52543e5ba5 100644 (file)
@@ -764,12 +764,15 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
        if (IS_ERR(i2c->clk))
                return PTR_ERR(i2c->clk);
 
-       clk_prepare_enable(i2c->clk);
+       ret = clk_prepare_enable(i2c->clk);
+       if (ret)
+               return ret;
 
-       if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-                                &clk_freq)) {
+       ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                                  &clk_freq);
+       if (ret) {
                dev_err(&pdev->dev, "clock-frequency not specified in DT");
-               return clk_freq;
+               goto err;
        }
 
        i2c->speed = clk_freq / 1000;
@@ -790,10 +793,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
        i2c->irq = platform_get_irq(pdev, 0);
        ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
                               dev_name(&pdev->dev), i2c);
-       if (ret) {
-               ret = -ENODEV;
+       if (ret)
                goto err;
-       }
 
        ret = i2c_add_adapter(&i2c->adap);
        if (ret < 0) {
index d1c22e3fdd146a34d96adcdd35b81a6e15984824..fc9bf7f30e355dfadfcadd4f7d8f187f818e9566 100644 (file)
@@ -1247,7 +1247,14 @@ static void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
        u32 reg;
 
        reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+       /* enable test mode */
        reg |= OMAP_I2C_SYSTEST_ST_EN;
+       /* select SDA/SCL IO mode */
+       reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT;
+       /* set SCL to high-impedance state (reset value is 0) */
+       reg |= OMAP_I2C_SYSTEST_SCL_O;
+       /* set SDA to high-impedance state (reset value is 0) */
+       reg |= OMAP_I2C_SYSTEST_SDA_O;
        omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
 }
 
@@ -1257,7 +1264,11 @@ static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
        u32 reg;
 
        reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
+       /* restore reset values */
        reg &= ~OMAP_I2C_SYSTEST_ST_EN;
+       reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK;
+       reg &= ~OMAP_I2C_SYSTEST_SCL_O;
+       reg &= ~OMAP_I2C_SYSTEST_SDA_O;
        omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
 }
 
index dcca7076231eda0d458916963d6f61eaf7ebfacb..1c9cb65ac4cf8aeb83becaec867f9a34f28b5a1e 100644 (file)
@@ -419,6 +419,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev)
        rc = i2c_add_adapter(adapter);
        if (rc) {
                dev_err(&pdev->dev, "Adapter registeration failed\n");
+               mbox_free_channel(ctx->mbox_chan);
                return rc;
        }
 
index 069a41f116ddcd0831d2adb65acac6709ee9e8c6..c83e4d13cfc5c402dfdea64df08f399ab486822b 100644 (file)
@@ -567,6 +567,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
        if (bri->prepare_recovery)
                bri->prepare_recovery(adap);
 
+       bri->set_scl(adap, val);
+       ndelay(RECOVERY_NDELAY);
+
        /*
         * By this time SCL is high, as we need to give 9 falling-rising edges
         */
@@ -597,7 +600,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
 
 int i2c_generic_scl_recovery(struct i2c_adapter *adap)
 {
-       adap->bus_recovery_info->set_scl(adap, 1);
        return i2c_generic_recovery(adap);
 }
 EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
@@ -1012,6 +1014,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
  */
 void i2c_unregister_device(struct i2c_client *client)
 {
+       if (client->dev.of_node)
+               of_node_clear_flag(client->dev.of_node, OF_POPULATED);
        device_unregister(&client->dev);
 }
 EXPORT_SYMBOL_GPL(i2c_unregister_device);
@@ -1320,8 +1324,11 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
 
        dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
 
-       for_each_available_child_of_node(adap->dev.of_node, node)
+       for_each_available_child_of_node(adap->dev.of_node, node) {
+               if (of_node_test_and_set_flag(node, OF_POPULATED))
+                       continue;
                of_i2c_register_device(adap, node);
+       }
 }
 
 static int of_dev_node_match(struct device *dev, void *data)
@@ -1333,13 +1340,17 @@ static int of_dev_node_match(struct device *dev, void *data)
 struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 {
        struct device *dev;
+       struct i2c_client *client;
 
-       dev = bus_find_device(&i2c_bus_type, NULL, node,
-                                        of_dev_node_match);
+       dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
        if (!dev)
                return NULL;
 
-       return i2c_verify_client(dev);
+       client = i2c_verify_client(dev);
+       if (!client)
+               put_device(dev);
+
+       return client;
 }
 EXPORT_SYMBOL(of_find_i2c_device_by_node);
 
@@ -1347,13 +1358,17 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node);
 struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
 {
        struct device *dev;
+       struct i2c_adapter *adapter;
 
-       dev = bus_find_device(&i2c_bus_type, NULL, node,
-                                        of_dev_node_match);
+       dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
        if (!dev)
                return NULL;
 
-       return i2c_verify_adapter(dev);
+       adapter = i2c_verify_adapter(dev);
+       if (!adapter)
+               put_device(dev);
+
+       return adapter;
 }
 EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
 #else
@@ -1853,6 +1868,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
                if (adap == NULL)
                        return NOTIFY_OK;       /* not for us */
 
+               if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
+                       put_device(&adap->dev);
+                       return NOTIFY_OK;
+               }
+
                client = of_i2c_register_device(adap, rd->dn);
                put_device(&adap->dev);
 
@@ -1863,6 +1883,10 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
                }
                break;
        case OF_RECONFIG_CHANGE_REMOVE:
+               /* already depopulated? */
+               if (!of_node_check_flag(rd->dn, OF_POPULATED))
+                       return NOTIFY_OK;
+
                /* find our device by node */
                client = of_find_i2c_device_by_node(rd->dn);
                if (client == NULL)
index 8223746546093c7a08f4bdfc8425459d88fe1a52..1da44961477953038e78409169f80a3f4884f89a 100644 (file)
@@ -80,9 +80,6 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count > attr->size)
-               return -EFBIG;
-
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
 
        spin_lock_irqsave(&eeprom->buffer_lock, flags);
@@ -98,9 +95,6 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count > attr->size)
-               return -EFBIG;
-
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
 
        spin_lock_irqsave(&eeprom->buffer_lock, flags);
index 4e70f51c237089f54ebee9882df499551d56b1e3..cc5a35750b507359f6496c980d30bdb7027ded76 100644 (file)
@@ -1464,7 +1464,7 @@ static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
 {
        int i;
 
-       for (i = from; i >= 0; i++) {
+       for (i = from; i >= 0; i--) {
                if (data->triggers[i].indio_trig) {
                        iio_trigger_unregister(data->triggers[i].indio_trig);
                        data->triggers[i].indio_trig = NULL;
index e8e2077c7244b5623efc8cd07521a9105dfbe192..13ea1ea23328501f4969c5453e603cf67e5b81b2 100644 (file)
@@ -557,21 +557,21 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
        if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
                iio_push_event(indio_dev,
                               IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
-                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_TYPE_MAG,
                                                  IIO_EV_DIR_RISING),
                               ts);
 
        if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
                iio_push_event(indio_dev,
                               IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
-                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_TYPE_MAG,
                                                  IIO_EV_DIR_RISING),
                               ts);
 
        if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
                iio_push_event(indio_dev,
                               IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
-                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_TYPE_MAG,
                                                  IIO_EV_DIR_RISING),
                               ts);
 }
@@ -644,7 +644,7 @@ static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
 
 static const struct iio_event_spec mma8452_transient_event[] = {
        {
-               .type = IIO_EV_TYPE_THRESH,
+               .type = IIO_EV_TYPE_MAG,
                .dir = IIO_EV_DIR_RISING,
                .mask_separate = BIT(IIO_EV_INFO_ENABLE),
                .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
index 7c5565891cb83012f9034b3e9224629c08a00ced..eb0cd897714a26b619b9e6c924ce4c3a65a5806b 100644 (file)
@@ -153,8 +153,7 @@ config DA9150_GPADC
 
 config CC10001_ADC
        tristate "Cosmic Circuits 10001 ADC driver"
-       depends on HAVE_CLK || REGULATOR
-       depends on HAS_IOMEM
+       depends on HAS_IOMEM && HAVE_CLK && REGULATOR
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index 8a0eb4a04fb55b9cb2436db5b16f678f654b8a26..7b40925dd4ff297e56fa0a3541980e9964d14092 100644 (file)
@@ -182,7 +182,7 @@ struct at91_adc_caps {
        u8      ts_pen_detect_sensitivity;
 
        /* startup time calculate function */
-       u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
+       u32 (*calc_startup_ticks)(u32 startup_time, u32 adc_clk_khz);
 
        u8      num_channels;
        struct at91_adc_reg_desc registers;
@@ -201,7 +201,7 @@ struct at91_adc_state {
        u8                      num_channels;
        void __iomem            *reg_base;
        struct at91_adc_reg_desc *registers;
-       u                     startup_time;
+       u32                     startup_time;
        u8                      sample_hold_time;
        bool                    sleep_mode;
        struct iio_trigger      **trig;
@@ -779,7 +779,7 @@ ret:
        return ret;
 }
 
-static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz)
+static u32 calc_startup_ticks_9260(u32 startup_time, u32 adc_clk_khz)
 {
        /*
         * Number of ticks needed to cover the startup time of the ADC
@@ -790,7 +790,7 @@ static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz)
        return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8;
 }
 
-static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
+static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz)
 {
        /*
         * For sama5d3x and at91sam9x5, the formula changes to:
index 8d9c9b9215ddc1ef5530df512d475a618cb71d8f..d819823f725747e5cd4ac8bcb50d3d833093ed2c 100644 (file)
@@ -299,6 +299,8 @@ static int mcp320x_probe(struct spi_device *spi)
        indio_dev->channels = chip_info->channels;
        indio_dev->num_channels = chip_info->num_channels;
 
+       adc->chip_info = chip_info;
+
        adc->transfer[0].tx_buf = &adc->tx_buf;
        adc->transfer[0].len = sizeof(adc->tx_buf);
        adc->transfer[1].rx_buf = adc->rx_buf;
index 8d4e019ea4ca5d0c3c773b6552b613b484c4b570..9c311c1e1ac7f89cef190a3445507025fdb8f131 100644 (file)
@@ -349,3 +349,7 @@ static struct platform_driver rockchip_saradc_driver = {
 };
 
 module_platform_driver(rockchip_saradc_driver);
+
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("Rockchip SARADC driver");
+MODULE_LICENSE("GPL v2");
index 06f4792240f025ac56b9cc42946cc4834f0ad480..ebe415f1064000c95c88f5d20da48a7f52f71d84 100644 (file)
@@ -833,7 +833,8 @@ static int twl4030_madc_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                   twl4030_madc_threaded_irq_handler,
-                                  IRQF_TRIGGER_RISING, "twl4030_madc", madc);
+                                  IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                  "twl4030_madc", madc);
        if (ret) {
                dev_err(&pdev->dev, "could not request irq\n");
                goto err_i2c;
index 480f335a0f9faee31bc6b2ac14f7899f18d6c9be..819632bf1fda7fee8fddd2acb3c02d9ff112b1ff 100644 (file)
@@ -635,7 +635,7 @@ static int vf610_adc_reg_access(struct iio_dev *indio_dev,
        struct vf610_adc *info = iio_priv(indio_dev);
 
        if ((readval == NULL) ||
-               (!(reg % 4) || (reg > VF610_REG_ADC_PCTL)))
+               ((reg % 4) || (reg > VF610_REG_ADC_PCTL)))
                return -EINVAL;
 
        *readval = readl(info->regs + reg);
index 610fc98f88efa4f05fd996505f45411756a50fb1..595511022795f6d917a1c14ae36a7a7267f74602 100644 (file)
@@ -36,6 +36,8 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
        s32 poll_value = 0;
 
        if (state) {
+               if (!atomic_read(&st->user_requested_state))
+                       return 0;
                if (sensor_hub_device_open(st->hsdev))
                        return -EIO;
 
@@ -52,8 +54,12 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
 
                poll_value = hid_sensor_read_poll_value(st);
        } else {
-               if (!atomic_dec_and_test(&st->data_ready))
+               int val;
+
+               val = atomic_dec_if_positive(&st->data_ready);
+               if (val < 0)
                        return 0;
+
                sensor_hub_device_close(st->hsdev);
                state_val = hid_sensor_get_usage_index(st->hsdev,
                        st->power_state.report_id,
@@ -92,9 +98,11 @@ EXPORT_SYMBOL(hid_sensor_power_state);
 
 int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
 {
+
 #ifdef CONFIG_PM
        int ret;
 
+       atomic_set(&st->user_requested_state, state);
        if (state)
                ret = pm_runtime_get_sync(&st->pdev->dev);
        else {
@@ -109,6 +117,7 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
 
        return 0;
 #else
+       atomic_set(&st->user_requested_state, state);
        return _hid_sensor_power_state(st, state);
 #endif
 }
index 61bb9d4239eafdacf6f6d5f8cdb7238537d2c376..e98428df0d44781e557ed2dfcf96017ad7d48baf 100644 (file)
@@ -22,7 +22,7 @@
 #include "ad5624r.h"
 
 static int ad5624r_spi_write(struct spi_device *spi,
-                            u8 cmd, u8 addr, u16 val, u8 len)
+                            u8 cmd, u8 addr, u16 val, u8 shift)
 {
        u32 data;
        u8 msg[3];
@@ -35,7 +35,7 @@ static int ad5624r_spi_write(struct spi_device *spi,
         * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits,
         * for the AD5664R, AD5644R, and AD5624R, respectively.
         */
-       data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
+       data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << shift);
        msg[0] = data >> 16;
        msg[1] = data >> 8;
        msg[2] = data;
index 17d4bb15be4d2998681f203b5944c5c82ce606ea..65ce86837177158aba7e4d5fd2064e0731129369 100644 (file)
@@ -431,6 +431,23 @@ static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val)
        return -EINVAL;
 }
 
+static int inv_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                struct iio_chan_spec const *chan, long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               switch (chan->type) {
+               case IIO_ANGL_VEL:
+                       return IIO_VAL_INT_PLUS_NANO;
+               default:
+                       return IIO_VAL_INT_PLUS_MICRO;
+               }
+       default:
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+
+       return -EINVAL;
+}
 static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val)
 {
        int result, i;
@@ -696,6 +713,7 @@ static const struct iio_info mpu_info = {
        .driver_module = THIS_MODULE,
        .read_raw = &inv_mpu6050_read_raw,
        .write_raw = &inv_mpu6050_write_raw,
+       .write_raw_get_fmt = &inv_write_raw_get_fmt,
        .attrs = &inv_attribute_group,
        .validate_trigger = inv_mpu6050_validate_trigger,
 };
index e6198b7c9cbfcf55a04b12049ccedbf3800e9b83..a5c59251ec0e93b90eeefee7637556629a32ede6 100644 (file)
@@ -188,6 +188,7 @@ config SENSORS_LM3533
 config LTR501
        tristate "LTR-501ALS-01 light sensor"
        depends on I2C
+       select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
@@ -201,6 +202,7 @@ config LTR501
 config STK3310
        tristate "STK3310 ALS and proximity sensor"
        depends on I2C
+       select REGMAP_I2C
        help
         Say yes here to get support for the Sensortek STK3310 ambient light
         and proximity sensor. The STK3311 model is also supported by this
index 869033e48a1facdd4021e3c9d2889d9fc7ab0773..a1d4905cc9d2d9680d5b3972233948fef3114035 100644 (file)
@@ -123,7 +123,7 @@ static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
        for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {
                if (val == cm3323_int_time[i].val &&
                    val2 == cm3323_int_time[i].val2) {
-                       reg_conf = data->reg_conf;
+                       reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK;
                        reg_conf |= i << CM3323_CONF_IT_SHIFT;
 
                        ret = i2c_smbus_write_word_data(data->client,
index 1ef7d3773ab90b4ee54dd69656f95899daed0f56..b5a0e66b5f282f09941dddf58de1b51eed3e71c2 100644 (file)
@@ -1302,7 +1302,7 @@ static int ltr501_init(struct ltr501_data *data)
        if (ret < 0)
                return ret;
 
-       data->als_contr = ret | data->chip_info->als_mode_active;
+       data->als_contr = status | data->chip_info->als_mode_active;
 
        ret = regmap_read(data->regmap, LTR501_PS_CONTR, &status);
        if (ret < 0)
index fee4297d7c8f8e039dd1716c655deff831f01a84..11a027adc204aeb630c66707eaf9d5d0ce169ebb 100644 (file)
@@ -43,7 +43,6 @@
 #define STK3311_CHIP_ID_VAL                    0x1D
 #define STK3310_PSINT_EN                       0x01
 #define STK3310_PS_MAX_VAL                     0xFFFF
-#define STK3310_THRESH_MAX                     0xFFFF
 
 #define STK3310_DRIVER_NAME                    "stk3310"
 #define STK3310_REGMAP_NAME                    "stk3310_regmap"
@@ -84,15 +83,13 @@ static const struct reg_field stk3310_reg_field_flag_psint =
                                REG_FIELD(STK3310_REG_FLAG, 4, 4);
 static const struct reg_field stk3310_reg_field_flag_nf =
                                REG_FIELD(STK3310_REG_FLAG, 0, 0);
-/*
- * Maximum PS values with regard to scale. Used to export the 'inverse'
- * PS value (high values for far objects, low values for near objects).
- */
+
+/* Estimate maximum proximity values with regard to measurement scale. */
 static const int stk3310_ps_max[4] = {
-       STK3310_PS_MAX_VAL / 64,
-       STK3310_PS_MAX_VAL / 16,
-       STK3310_PS_MAX_VAL /  4,
-       STK3310_PS_MAX_VAL,
+       STK3310_PS_MAX_VAL / 640,
+       STK3310_PS_MAX_VAL / 160,
+       STK3310_PS_MAX_VAL /  40,
+       STK3310_PS_MAX_VAL /  10
 };
 
 static const int stk3310_scale_table[][2] = {
@@ -128,14 +125,14 @@ static const struct iio_event_spec stk3310_events[] = {
        /* Proximity event */
        {
                .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_FALLING,
+               .dir = IIO_EV_DIR_RISING,
                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
                                 BIT(IIO_EV_INFO_ENABLE),
        },
        /* Out-of-proximity event */
        {
                .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_RISING,
+               .dir = IIO_EV_DIR_FALLING,
                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
                                 BIT(IIO_EV_INFO_ENABLE),
        },
@@ -203,25 +200,18 @@ static int stk3310_read_event(struct iio_dev *indio_dev,
                              int *val, int *val2)
 {
        u8 reg;
-       u16 buf;
+       __be16 buf;
        int ret;
-       unsigned int index;
        struct stk3310_data *data = iio_priv(indio_dev);
 
        if (info != IIO_EV_INFO_VALUE)
                return -EINVAL;
 
-       /*
-        * Only proximity interrupts are implemented at the moment.
-        * Since we're inverting proximity values, the sensor's 'high'
-        * threshold will become our 'low' threshold, associated with
-        * 'near' events. Similarly, the sensor's 'low' threshold will
-        * be our 'high' threshold, associated with 'far' events.
-        */
+       /* Only proximity interrupts are implemented at the moment. */
        if (dir == IIO_EV_DIR_RISING)
-               reg = STK3310_REG_THDL_PS;
-       else if (dir == IIO_EV_DIR_FALLING)
                reg = STK3310_REG_THDH_PS;
+       else if (dir == IIO_EV_DIR_FALLING)
+               reg = STK3310_REG_THDL_PS;
        else
                return -EINVAL;
 
@@ -232,8 +222,7 @@ static int stk3310_read_event(struct iio_dev *indio_dev,
                dev_err(&data->client->dev, "register read failed\n");
                return ret;
        }
-       regmap_field_read(data->reg_ps_gain, &index);
-       *val = swab16(stk3310_ps_max[index] - buf);
+       *val = be16_to_cpu(buf);
 
        return IIO_VAL_INT;
 }
@@ -246,7 +235,7 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
                               int val, int val2)
 {
        u8 reg;
-       u16 buf;
+       __be16 buf;
        int ret;
        unsigned int index;
        struct stk3310_data *data = iio_priv(indio_dev);
@@ -257,13 +246,13 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
                return -EINVAL;
 
        if (dir == IIO_EV_DIR_RISING)
-               reg = STK3310_REG_THDL_PS;
-       else if (dir == IIO_EV_DIR_FALLING)
                reg = STK3310_REG_THDH_PS;
+       else if (dir == IIO_EV_DIR_FALLING)
+               reg = STK3310_REG_THDL_PS;
        else
                return -EINVAL;
 
-       buf = swab16(stk3310_ps_max[index] - val);
+       buf = cpu_to_be16(val);
        ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
        if (ret < 0)
                dev_err(&client->dev, "failed to set PS threshold!\n");
@@ -312,7 +301,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
                            int *val, int *val2, long mask)
 {
        u8 reg;
-       u16 buf;
+       __be16 buf;
        int ret;
        unsigned int index;
        struct stk3310_data *data = iio_priv(indio_dev);
@@ -333,15 +322,7 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
                        mutex_unlock(&data->lock);
                        return ret;
                }
-               *val = swab16(buf);
-               if (chan->type == IIO_PROXIMITY) {
-                       /*
-                        * Invert the proximity data so we return low values
-                        * for close objects and high values for far ones.
-                        */
-                       regmap_field_read(data->reg_ps_gain, &index);
-                       *val = stk3310_ps_max[index] - *val;
-               }
+               *val = be16_to_cpu(buf);
                mutex_unlock(&data->lock);
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_INT_TIME:
@@ -581,8 +562,8 @@ static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
        }
        event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
                                     IIO_EV_TYPE_THRESH,
-                                    (dir ? IIO_EV_DIR_RISING :
-                                           IIO_EV_DIR_FALLING));
+                                    (dir ? IIO_EV_DIR_FALLING :
+                                           IIO_EV_DIR_RISING));
        iio_push_event(indio_dev, event, data->timestamp);
 
        /* Reset the interrupt flag */
@@ -627,13 +608,7 @@ static int stk3310_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev, "device_register failed\n");
-               stk3310_set_state(data, STK3310_STATE_STANDBY);
-       }
-
-       if (client->irq <= 0)
+       if (client->irq < 0)
                client->irq = stk3310_gpio_probe(client);
 
        if (client->irq >= 0) {
@@ -648,6 +623,12 @@ static int stk3310_probe(struct i2c_client *client,
                                        client->irq);
        }
 
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "device_register failed\n");
+               stk3310_set_state(data, STK3310_STATE_STANDBY);
+       }
+
        return ret;
 }
 
index 71c2bde275aac65ef8b7eb2f756fb05acb4e1958..f8b1df018abeeba410c19dc48bd9723663973977 100644 (file)
@@ -185,7 +185,7 @@ static int tcs3414_write_raw(struct iio_dev *indio_dev,
                if (val != 0)
                        return -EINVAL;
                for (i = 0; i < ARRAY_SIZE(tcs3414_times); i++) {
-                       if (val == tcs3414_times[i] * 1000) {
+                       if (val2 == tcs3414_times[i] * 1000) {
                                data->timing &= ~TCS3414_INTEG_MASK;
                                data->timing |= i;
                                return i2c_smbus_write_byte_data(
index dcadfc4f06619a1a147d560581bb7bfabdd3f663..efb9350b0d766a0915a2c091c04b9bdea15c5d4e 100644 (file)
@@ -90,6 +90,7 @@ config IIO_ST_MAGN_SPI_3AXIS
 config BMC150_MAGN
        tristate "Bosch BMC150 Magnetometer Driver"
        depends on I2C
+       select REGMAP_I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index d4c1788699911e934fc3c1baffa3de8928ac26a6..1347a1f2e46f8194bad0bfe49bd91ea6a948ac8e 100644 (file)
@@ -706,11 +706,11 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
                goto err_poweroff;
        }
        if (chip_id != BMC150_MAGN_CHIP_ID_VAL) {
-               dev_err(&data->client->dev, "Invalid chip id 0x%x\n", ret);
+               dev_err(&data->client->dev, "Invalid chip id 0x%x\n", chip_id);
                ret = -ENODEV;
                goto err_poweroff;
        }
-       dev_dbg(&data->client->dev, "Chip id %x\n", ret);
+       dev_dbg(&data->client->dev, "Chip id %x\n", chip_id);
 
        preset = bmc150_magn_presets_table[BMC150_MAGN_DEFAULT_PRESET];
        ret = bmc150_magn_set_odr(data, preset.odr);
index 7a2ea71c659a0162baf0591af149045c36224d1b..706ebfd6297fa7c0a311a80bfcb431b533d2cc70 100644 (file)
 #define MMC35240_OTP_START_ADDR                0x1B
 
 enum mmc35240_resolution {
-       MMC35240_16_BITS_SLOW = 0, /* 100 Hz */
-       MMC35240_16_BITS_FAST,     /* 200 Hz */
-       MMC35240_14_BITS,          /* 333 Hz */
-       MMC35240_12_BITS,          /* 666 Hz */
+       MMC35240_16_BITS_SLOW = 0, /* 7.92 ms */
+       MMC35240_16_BITS_FAST,     /* 4.08 ms */
+       MMC35240_14_BITS,          /* 2.16 ms */
+       MMC35240_12_BITS,          /* 1.20 ms */
 };
 
 enum mmc35240_axis {
@@ -100,22 +100,22 @@ static const struct {
        int sens[3]; /* sensitivity per X, Y, Z axis */
        int nfo; /* null field output */
 } mmc35240_props_table[] = {
-       /* 16 bits, 100Hz ODR */
+       /* 16 bits, 125Hz ODR */
        {
                {1024, 1024, 1024},
                32768,
        },
-       /* 16 bits, 200Hz ODR */
+       /* 16 bits, 250Hz ODR */
        {
                {1024, 1024, 770},
                32768,
        },
-       /* 14 bits, 333Hz ODR */
+       /* 14 bits, 450Hz ODR */
        {
                {256, 256, 193},
                8192,
        },
-       /* 12 bits, 666Hz ODR */
+       /* 12 bits, 800Hz ODR */
        {
                {64, 64, 48},
                2048,
@@ -133,9 +133,15 @@ struct mmc35240_data {
        int axis_scale[3];
 };
 
-static const int mmc35240_samp_freq[] = {100, 200, 333, 666};
+static const struct {
+       int val;
+       int val2;
+} mmc35240_samp_freq[] = { {1, 500000},
+                          {13, 0},
+                          {25, 0},
+                          {50, 0} };
 
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 333 666");
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1.5 13 25 50");
 
 #define MMC35240_CHANNEL(_axis) { \
        .type = IIO_MAGN, \
@@ -168,7 +174,8 @@ static int mmc35240_get_samp_freq_index(struct mmc35240_data *data,
        int i;
 
        for (i = 0; i < ARRAY_SIZE(mmc35240_samp_freq); i++)
-               if (mmc35240_samp_freq[i] == val)
+               if (mmc35240_samp_freq[i].val == val &&
+                   mmc35240_samp_freq[i].val2 == val2)
                        return i;
        return -EINVAL;
 }
@@ -195,8 +202,8 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
                coil_bit = MMC35240_CTRL0_RESET_BIT;
 
        return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
-                                 MMC35240_CTRL0_REFILL_BIT,
-                                 coil_bit);
+                                 coil_bit, coil_bit);
+
 }
 
 static int mmc35240_init(struct mmc35240_data *data)
@@ -215,14 +222,15 @@ static int mmc35240_init(struct mmc35240_data *data)
 
        /*
         * make sure we restore sensor characteristics, by doing
-        * a RESET/SET sequence
+        * a SET/RESET sequence, the axis polarity being naturally
+        * aligned after RESET
         */
-       ret = mmc35240_hw_set(data, false);
+       ret = mmc35240_hw_set(data, true);
        if (ret < 0)
                return ret;
        usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1);
 
-       ret = mmc35240_hw_set(data, true);
+       ret = mmc35240_hw_set(data, false);
        if (ret < 0)
                return ret;
 
@@ -378,9 +386,9 @@ static int mmc35240_read_raw(struct iio_dev *indio_dev,
                if (i < 0 || i >= ARRAY_SIZE(mmc35240_samp_freq))
                        return -EINVAL;
 
-               *val = mmc35240_samp_freq[i];
-               *val2 = 0;
-               return IIO_VAL_INT;
+               *val = mmc35240_samp_freq[i].val;
+               *val2 = mmc35240_samp_freq[i].val2;
+               return IIO_VAL_INT_PLUS_MICRO;
        default:
                return -EINVAL;
        }
@@ -496,6 +504,7 @@ static int mmc35240_probe(struct i2c_client *client,
        }
 
        data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
        data->client = client;
        data->regmap = regmap;
        data->res = MMC35240_16_BITS_SLOW;
index 2042e375f8351de6dc04b0b6ae7861702d17c6cf..3d756bd8c703230bfc93f530d03399f9f5e1413f 100644 (file)
@@ -80,6 +80,7 @@
 #define SX9500_COMPSTAT_MASK           GENMASK(3, 0)
 
 #define SX9500_NUM_CHANNELS            4
+#define SX9500_CHAN_MASK               GENMASK(SX9500_NUM_CHANNELS - 1, 0)
 
 struct sx9500_data {
        struct mutex mutex;
@@ -281,7 +282,7 @@ static int sx9500_read_prox_data(struct sx9500_data *data,
        if (ret < 0)
                return ret;
 
-       *val = 32767 - (s16)be16_to_cpu(regval);
+       *val = be16_to_cpu(regval);
 
        return IIO_VAL_INT;
 }
@@ -329,20 +330,20 @@ static int sx9500_read_proximity(struct sx9500_data *data,
        else
                ret = sx9500_wait_for_sample(data);
 
-       if (ret < 0)
-               return ret;
-
        mutex_lock(&data->mutex);
 
-       ret = sx9500_read_prox_data(data, chan, val);
        if (ret < 0)
-               goto out;
+               goto out_dec_data_rdy;
 
-       ret = sx9500_dec_chan_users(data, chan->channel);
+       ret = sx9500_read_prox_data(data, chan, val);
        if (ret < 0)
-               goto out;
+               goto out_dec_data_rdy;
 
        ret = sx9500_dec_data_rdy_users(data);
+       if (ret < 0)
+               goto out_dec_chan;
+
+       ret = sx9500_dec_chan_users(data, chan->channel);
        if (ret < 0)
                goto out;
 
@@ -350,6 +351,8 @@ static int sx9500_read_proximity(struct sx9500_data *data,
 
        goto out;
 
+out_dec_data_rdy:
+       sx9500_dec_data_rdy_users(data);
 out_dec_chan:
        sx9500_dec_chan_users(data, chan->channel);
 out:
@@ -679,7 +682,7 @@ out:
 static int sx9500_buffer_preenable(struct iio_dev *indio_dev)
 {
        struct sx9500_data *data = iio_priv(indio_dev);
-       int ret, i;
+       int ret = 0, i;
 
        mutex_lock(&data->mutex);
 
@@ -703,7 +706,7 @@ static int sx9500_buffer_preenable(struct iio_dev *indio_dev)
 static int sx9500_buffer_predisable(struct iio_dev *indio_dev)
 {
        struct sx9500_data *data = iio_priv(indio_dev);
-       int ret, i;
+       int ret = 0, i;
 
        iio_triggered_buffer_predisable(indio_dev);
 
@@ -800,8 +803,7 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev)
        unsigned int val;
 
        ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
-                                GENMASK(SX9500_NUM_CHANNELS, 0),
-                                GENMASK(SX9500_NUM_CHANNELS, 0));
+                                SX9500_CHAN_MASK, SX9500_CHAN_MASK);
        if (ret < 0)
                return ret;
 
@@ -821,7 +823,7 @@ static int sx9500_init_compensation(struct iio_dev *indio_dev)
 
 out:
        regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
-                          GENMASK(SX9500_NUM_CHANNELS, 0), 0);
+                          SX9500_CHAN_MASK, 0);
        return ret;
 }
 
index cb2e8ad8bfdcd02e75b9ea4f82e31c598e95109e..7a2b639eaa96e2ea440f3102c5da101d41edcd2b 100644 (file)
@@ -204,7 +204,7 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
                *val = ret;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
-               *val = 13657;
+               *val = -13657;
                *val2 = 500000;
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_SCALE:
index fcc49f89b9464cfa8d6206602c6b1f2d518c9ecc..8f21f32f9739e23f9558e8b38434daa5a5856f3e 100644 (file)
@@ -132,6 +132,9 @@ static int tmp006_write_raw(struct iio_dev *indio_dev,
        struct tmp006_data *data = iio_priv(indio_dev);
        int i;
 
+       if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+               return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++)
                if ((val == tmp006_freqs[i][0]) &&
                    (val2 == tmp006_freqs[i][1])) {
index c7dcfe4ca5f10219e553cd4cb5acdd2e1658c95b..0429040304fd478a7ad7833df48c0bdc74c429bc 100644 (file)
@@ -88,7 +88,7 @@ void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *
        struct ib_ah *ah;
        struct ib_mad_send_wr_private *mad_send_wr;
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH)
+       if (rdma_cap_ib_switch(device))
                port_priv = ib_get_agent_port(device, 0);
        else
                port_priv = ib_get_agent_port(device, port_num);
@@ -122,7 +122,7 @@ void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *
        memcpy(send_buf->mad, mad_hdr, resp_mad_len);
        send_buf->ah = ah;
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH) {
+       if (rdma_cap_ib_switch(device)) {
                mad_send_wr = container_of(send_buf,
                                           struct ib_mad_send_wr_private,
                                           send_buf);
index dbddddd6fb5d111e94e44e2800282c84312131a0..3a972ebf3c0d1170efe280aa7bcf781c831fa98f 100644 (file)
@@ -169,6 +169,7 @@ struct cm_device {
        struct ib_device *ib_device;
        struct device *device;
        u8 ack_delay;
+       int going_down;
        struct cm_port *port[0];
 };
 
@@ -805,6 +806,11 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
 {
        int wait_time;
        unsigned long flags;
+       struct cm_device *cm_dev;
+
+       cm_dev = ib_get_client_data(cm_id_priv->id.device, &cm_client);
+       if (!cm_dev)
+               return;
 
        spin_lock_irqsave(&cm.lock, flags);
        cm_cleanup_timewait(cm_id_priv->timewait_info);
@@ -818,8 +824,14 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
         */
        cm_id_priv->id.state = IB_CM_TIMEWAIT;
        wait_time = cm_convert_to_ms(cm_id_priv->av.timeout);
-       queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
-                          msecs_to_jiffies(wait_time));
+
+       /* Check if the device started its remove_one */
+       spin_lock_irq(&cm.lock);
+       if (!cm_dev->going_down)
+               queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
+                                  msecs_to_jiffies(wait_time));
+       spin_unlock_irq(&cm.lock);
+
        cm_id_priv->timewait_info = NULL;
 }
 
@@ -3305,6 +3317,11 @@ static int cm_establish(struct ib_cm_id *cm_id)
        struct cm_work *work;
        unsigned long flags;
        int ret = 0;
+       struct cm_device *cm_dev;
+
+       cm_dev = ib_get_client_data(cm_id->device, &cm_client);
+       if (!cm_dev)
+               return -ENODEV;
 
        work = kmalloc(sizeof *work, GFP_ATOMIC);
        if (!work)
@@ -3343,7 +3360,17 @@ static int cm_establish(struct ib_cm_id *cm_id)
        work->remote_id = cm_id->remote_id;
        work->mad_recv_wc = NULL;
        work->cm_event.event = IB_CM_USER_ESTABLISHED;
-       queue_delayed_work(cm.wq, &work->work, 0);
+
+       /* Check if the device started its remove_one */
+       spin_lock_irq(&cm.lock);
+       if (!cm_dev->going_down) {
+               queue_delayed_work(cm.wq, &work->work, 0);
+       } else {
+               kfree(work);
+               ret = -ENODEV;
+       }
+       spin_unlock_irq(&cm.lock);
+
 out:
        return ret;
 }
@@ -3394,6 +3421,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
        enum ib_cm_event_type event;
        u16 attr_id;
        int paths = 0;
+       int going_down = 0;
 
        switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
        case CM_REQ_ATTR_ID:
@@ -3452,7 +3480,19 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
        work->cm_event.event = event;
        work->mad_recv_wc = mad_recv_wc;
        work->port = port;
-       queue_delayed_work(cm.wq, &work->work, 0);
+
+       /* Check if the device started its remove_one */
+       spin_lock_irq(&cm.lock);
+       if (!port->cm_dev->going_down)
+               queue_delayed_work(cm.wq, &work->work, 0);
+       else
+               going_down = 1;
+       spin_unlock_irq(&cm.lock);
+
+       if (going_down) {
+               kfree(work);
+               ib_free_recv_mad(mad_recv_wc);
+       }
 }
 
 static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
@@ -3771,7 +3811,7 @@ static void cm_add_one(struct ib_device *ib_device)
 
        cm_dev->ib_device = ib_device;
        cm_get_ack_delay(cm_dev);
-
+       cm_dev->going_down = 0;
        cm_dev->device = device_create(&cm_class, &ib_device->dev,
                                       MKDEV(0, 0), NULL,
                                       "%s", ib_device->name);
@@ -3864,14 +3904,23 @@ static void cm_remove_one(struct ib_device *ib_device)
        list_del(&cm_dev->list);
        write_unlock_irqrestore(&cm.device_lock, flags);
 
+       spin_lock_irq(&cm.lock);
+       cm_dev->going_down = 1;
+       spin_unlock_irq(&cm.lock);
+
        for (i = 1; i <= ib_device->phys_port_cnt; i++) {
                if (!rdma_cap_ib_cm(ib_device, i))
                        continue;
 
                port = cm_dev->port[i-1];
                ib_modify_port(ib_device, port->port_num, 0, &port_modify);
-               ib_unregister_mad_agent(port->mad_agent);
+               /*
+                * We flush the queue here after the going_down set, this
+                * verify that no new works will be queued in the recv handler,
+                * after that we can call the unregister_mad_agent
+                */
                flush_workqueue(cm.wq);
+               ib_unregister_mad_agent(port->mad_agent);
                cm_remove_port_fs(port);
        }
        device_unregister(cm_dev->device);
index e6ffa2e66c1ac54b7a2645f59bbb28c00bc91cc3..22a3abee2a54c0fdce95a4567ef3cc45a20901ad 100644 (file)
@@ -67,7 +67,8 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
                err_str = "Invalid port mapper client";
                goto pid_query_error;
        }
-       if (iwpm_registered_client(nl_client))
+       if (iwpm_check_registration(nl_client, IWPM_REG_VALID) ||
+                       iwpm_user_pid == IWPM_PID_UNAVAILABLE)
                return 0;
        skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REG_PID, &nlh, nl_client);
        if (!skb) {
@@ -106,7 +107,6 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
        ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
        if (ret) {
                skb = NULL; /* skb is freed in the netlink send-op handling */
-               iwpm_set_registered(nl_client, 1);
                iwpm_user_pid = IWPM_PID_UNAVAILABLE;
                err_str = "Unable to send a nlmsg";
                goto pid_query_error;
@@ -144,12 +144,12 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
                err_str = "Invalid port mapper client";
                goto add_mapping_error;
        }
-       if (!iwpm_registered_client(nl_client)) {
+       if (!iwpm_valid_pid())
+               return 0;
+       if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) {
                err_str = "Unregistered port mapper client";
                goto add_mapping_error;
        }
-       if (!iwpm_valid_pid())
-               return 0;
        skb = iwpm_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, &nlh, nl_client);
        if (!skb) {
                err_str = "Unable to create a nlmsg";
@@ -214,12 +214,12 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
                err_str = "Invalid port mapper client";
                goto query_mapping_error;
        }
-       if (!iwpm_registered_client(nl_client)) {
+       if (!iwpm_valid_pid())
+               return 0;
+       if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) {
                err_str = "Unregistered port mapper client";
                goto query_mapping_error;
        }
-       if (!iwpm_valid_pid())
-               return 0;
        ret = -ENOMEM;
        skb = iwpm_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, &nlh, nl_client);
        if (!skb) {
@@ -288,12 +288,12 @@ int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
                err_str = "Invalid port mapper client";
                goto remove_mapping_error;
        }
-       if (!iwpm_registered_client(nl_client)) {
+       if (!iwpm_valid_pid())
+               return 0;
+       if (iwpm_check_registration(nl_client, IWPM_REG_UNDEF)) {
                err_str = "Unregistered port mapper client";
                goto remove_mapping_error;
        }
-       if (!iwpm_valid_pid())
-               return 0;
        skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, &nlh, nl_client);
        if (!skb) {
                ret = -ENOMEM;
@@ -388,7 +388,7 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
        pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
                        __func__, iwpm_user_pid);
        if (iwpm_valid_client(nl_client))
-               iwpm_set_registered(nl_client, 1);
+               iwpm_set_registration(nl_client, IWPM_REG_VALID);
 register_pid_response_exit:
        nlmsg_request->request_done = 1;
        /* always for found nlmsg_request */
@@ -644,7 +644,6 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX];
        const char *msg_type = "Mapping Info response";
-       int iwpm_pid;
        u8 nl_client;
        char *iwpm_name;
        u16 iwpm_version;
@@ -669,14 +668,14 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
                                __func__, nl_client);
                return ret;
        }
-       iwpm_set_registered(nl_client, 0);
+       iwpm_set_registration(nl_client, IWPM_REG_INCOMPL);
        atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
+       iwpm_user_pid = cb->nlh->nlmsg_pid;
        if (!iwpm_mapinfo_available())
                return 0;
-       iwpm_pid = cb->nlh->nlmsg_pid;
        pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
-                __func__, iwpm_pid);
-       ret = iwpm_send_mapinfo(nl_client, iwpm_pid);
+                __func__, iwpm_user_pid);
+       ret = iwpm_send_mapinfo(nl_client, iwpm_user_pid);
        return ret;
 }
 EXPORT_SYMBOL(iwpm_mapping_info_cb);
index a626795bf9c71f43f7d526d07ae3a490399fdb79..5fb089e913530c54a9852d4ae6fabcda24a00451 100644 (file)
@@ -78,6 +78,7 @@ init_exit:
        mutex_unlock(&iwpm_admin_lock);
        if (!ret) {
                iwpm_set_valid(nl_client, 1);
+               iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
                pr_debug("%s: Mapinfo and reminfo tables are created\n",
                                __func__);
        }
@@ -106,6 +107,7 @@ int iwpm_exit(u8 nl_client)
        }
        mutex_unlock(&iwpm_admin_lock);
        iwpm_set_valid(nl_client, 0);
+       iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
        return 0;
 }
 EXPORT_SYMBOL(iwpm_exit);
@@ -397,17 +399,23 @@ void iwpm_set_valid(u8 nl_client, int valid)
 }
 
 /* valid client */
-int iwpm_registered_client(u8 nl_client)
+u32 iwpm_get_registration(u8 nl_client)
 {
        return iwpm_admin.reg_list[nl_client];
 }
 
 /* valid client */
-void iwpm_set_registered(u8 nl_client, int reg)
+void iwpm_set_registration(u8 nl_client, u32 reg)
 {
        iwpm_admin.reg_list[nl_client] = reg;
 }
 
+/* valid client */
+u32 iwpm_check_registration(u8 nl_client, u32 reg)
+{
+       return (iwpm_get_registration(nl_client) & reg);
+}
+
 int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
                                struct sockaddr_storage *b_sockaddr)
 {
index ee2d9ff095be2d68d14c9c48eb551f9647ca562f..b7b9e194ce81fd8f2c7598bb2a6b58cab4fad6b8 100644 (file)
 #define IWPM_PID_UNDEFINED     -1
 #define IWPM_PID_UNAVAILABLE   -2
 
+#define IWPM_REG_UNDEF          0x01
+#define IWPM_REG_VALID          0x02
+#define IWPM_REG_INCOMPL        0x04
+
 struct iwpm_nlmsg_request {
        struct list_head    inprocess_list;
        __u32               nlmsg_seq;
@@ -88,7 +92,7 @@ struct iwpm_admin_data {
        atomic_t refcount;
        atomic_t nlmsg_seq;
        int      client_list[RDMA_NL_NUM_CLIENTS];
-       int      reg_list[RDMA_NL_NUM_CLIENTS];
+       u32      reg_list[RDMA_NL_NUM_CLIENTS];
 };
 
 /**
@@ -159,19 +163,31 @@ int iwpm_valid_client(u8 nl_client);
 void iwpm_set_valid(u8 nl_client, int valid);
 
 /**
- * iwpm_registered_client - Check if the port mapper client is registered
+ * iwpm_check_registration - Check if the client registration
+ *                           matches the given one
  * @nl_client: The index of the netlink client
+ * @reg: The given registration type to compare with
  *
  * Call iwpm_register_pid() to register a client
+ * Returns true if the client registration matches reg,
+ * otherwise returns false
+ */
+u32 iwpm_check_registration(u8 nl_client, u32 reg);
+
+/**
+ * iwpm_set_registration - Set the client registration
+ * @nl_client: The index of the netlink client
+ * @reg: Registration type to set
  */
-int iwpm_registered_client(u8 nl_client);
+void iwpm_set_registration(u8 nl_client, u32 reg);
 
 /**
- * iwpm_set_registered - Set the port mapper client to registered or not
+ * iwpm_get_registration
  * @nl_client: The index of the netlink client
- * @reg: 1 if registered or 0 if not
+ *
+ * Returns the client registration type
  */
-void iwpm_set_registered(u8 nl_client, int reg);
+u32 iwpm_get_registration(u8 nl_client);
 
 /**
  * iwpm_send_mapinfo - Send local and mapped IPv4/IPv6 address info of
index a4b1466c1bf686431db027309db9722c7b044455..786fc51bf04b22b0d9b0fc371f3fdb25ec4c811b 100644 (file)
@@ -769,7 +769,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
        bool opa = rdma_cap_opa_mad(mad_agent_priv->qp_info->port_priv->device,
                                    mad_agent_priv->qp_info->port_priv->port_num);
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH &&
+       if (rdma_cap_ib_switch(device) &&
            smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
                port_num = send_wr->wr.ud.port_num;
        else
@@ -787,14 +787,15 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
                if ((opa_get_smp_direction(opa_smp)
                     ? opa_smp->route.dr.dr_dlid : opa_smp->route.dr.dr_slid) ==
                     OPA_LID_PERMISSIVE &&
-                    opa_smi_handle_dr_smp_send(opa_smp, device->node_type,
+                    opa_smi_handle_dr_smp_send(opa_smp,
+                                               rdma_cap_ib_switch(device),
                                                port_num) == IB_SMI_DISCARD) {
                        ret = -EINVAL;
                        dev_err(&device->dev, "OPA Invalid directed route\n");
                        goto out;
                }
                opa_drslid = be32_to_cpu(opa_smp->route.dr.dr_slid);
-               if (opa_drslid != OPA_LID_PERMISSIVE &&
+               if (opa_drslid != be32_to_cpu(OPA_LID_PERMISSIVE) &&
                    opa_drslid & 0xffff0000) {
                        ret = -EINVAL;
                        dev_err(&device->dev, "OPA Invalid dr_slid 0x%x\n",
@@ -810,7 +811,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
        } else {
                if ((ib_get_smp_direction(smp) ? smp->dr_dlid : smp->dr_slid) ==
                     IB_LID_PERMISSIVE &&
-                    smi_handle_dr_smp_send(smp, device->node_type, port_num) ==
+                    smi_handle_dr_smp_send(smp, rdma_cap_ib_switch(device), port_num) ==
                     IB_SMI_DISCARD) {
                        ret = -EINVAL;
                        dev_err(&device->dev, "Invalid directed route\n");
@@ -2030,7 +2031,7 @@ static enum smi_action handle_ib_smi(const struct ib_mad_port_private *port_priv
        struct ib_smp *smp = (struct ib_smp *)recv->mad;
 
        if (smi_handle_dr_smp_recv(smp,
-                                  port_priv->device->node_type,
+                                  rdma_cap_ib_switch(port_priv->device),
                                   port_num,
                                   port_priv->device->phys_port_cnt) ==
                                   IB_SMI_DISCARD)
@@ -2042,13 +2043,13 @@ static enum smi_action handle_ib_smi(const struct ib_mad_port_private *port_priv
 
        if (retsmi == IB_SMI_SEND) { /* don't forward */
                if (smi_handle_dr_smp_send(smp,
-                                          port_priv->device->node_type,
+                                          rdma_cap_ib_switch(port_priv->device),
                                           port_num) == IB_SMI_DISCARD)
                        return IB_SMI_DISCARD;
 
                if (smi_check_local_smp(smp, port_priv->device) == IB_SMI_DISCARD)
                        return IB_SMI_DISCARD;
-       } else if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) {
+       } else if (rdma_cap_ib_switch(port_priv->device)) {
                /* forward case for switches */
                memcpy(response, recv, mad_priv_size(response));
                response->header.recv_wc.wc = &response->header.wc;
@@ -2115,7 +2116,7 @@ handle_opa_smi(struct ib_mad_port_private *port_priv,
        struct opa_smp *smp = (struct opa_smp *)recv->mad;
 
        if (opa_smi_handle_dr_smp_recv(smp,
-                                  port_priv->device->node_type,
+                                  rdma_cap_ib_switch(port_priv->device),
                                   port_num,
                                   port_priv->device->phys_port_cnt) ==
                                   IB_SMI_DISCARD)
@@ -2127,7 +2128,7 @@ handle_opa_smi(struct ib_mad_port_private *port_priv,
 
        if (retsmi == IB_SMI_SEND) { /* don't forward */
                if (opa_smi_handle_dr_smp_send(smp,
-                                          port_priv->device->node_type,
+                                          rdma_cap_ib_switch(port_priv->device),
                                           port_num) == IB_SMI_DISCARD)
                        return IB_SMI_DISCARD;
 
@@ -2135,7 +2136,7 @@ handle_opa_smi(struct ib_mad_port_private *port_priv,
                    IB_SMI_DISCARD)
                        return IB_SMI_DISCARD;
 
-       } else if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) {
+       } else if (rdma_cap_ib_switch(port_priv->device)) {
                /* forward case for switches */
                memcpy(response, recv, mad_priv_size(response));
                response->header.recv_wc.wc = &response->header.wc;
@@ -2235,7 +2236,7 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
                goto out;
        }
 
-       if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH)
+       if (rdma_cap_ib_switch(port_priv->device))
                port_num = wc->port_num;
        else
                port_num = port_priv->port_num;
@@ -3297,17 +3298,11 @@ static int ib_mad_port_close(struct ib_device *device, int port_num)
 
 static void ib_mad_init_device(struct ib_device *device)
 {
-       int start, end, i;
+       int start, i;
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH) {
-               start = 0;
-               end   = 0;
-       } else {
-               start = 1;
-               end   = device->phys_port_cnt;
-       }
+       start = rdma_start_port(device);
 
-       for (i = start; i <= end; i++) {
+       for (i = start; i <= rdma_end_port(device); i++) {
                if (!rdma_cap_ib_mad(device, i))
                        continue;
 
@@ -3342,17 +3337,9 @@ error:
 
 static void ib_mad_remove_device(struct ib_device *device)
 {
-       int start, end, i;
-
-       if (device->node_type == RDMA_NODE_IB_SWITCH) {
-               start = 0;
-               end   = 0;
-       } else {
-               start = 1;
-               end   = device->phys_port_cnt;
-       }
+       int i;
 
-       for (i = start; i <= end; i++) {
+       for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) {
                if (!rdma_cap_ib_mad(device, i))
                        continue;
 
index 1244f02a5c6d402aa5389e206b6b8e5482ec2de2..2cb865c7ce7a98773f338b1b8c09ffc66db4cebf 100644 (file)
@@ -812,12 +812,8 @@ static void mcast_add_one(struct ib_device *device)
        if (!dev)
                return;
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH)
-               dev->start_port = dev->end_port = 0;
-       else {
-               dev->start_port = 1;
-               dev->end_port = device->phys_port_cnt;
-       }
+       dev->start_port = rdma_start_port(device);
+       dev->end_port = rdma_end_port(device);
 
        for (i = 0; i <= dev->end_port - dev->start_port; i++) {
                if (!rdma_cap_ib_mcast(device, dev->start_port + i))
index 62d91bfa4cb70bed63cfac71a746fca544513aff..3bfab3505a2917d561d9d45372c091b38649151c 100644 (file)
 
 #include "smi.h"
 
-enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, u8 node_type,
+enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch,
                                       int port_num, int phys_port_cnt);
 int opa_smi_get_fwd_port(struct opa_smp *smp);
 extern enum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp);
 extern enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp,
-                                             u8 node_type, int port_num);
+                                             bool is_switch, int port_num);
 
 /*
  * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
index 0fae85062a65b8704ddc11a117751df62db9c9d4..ca919f4296664f070f0c63b1765542375818f0aa 100644 (file)
@@ -1156,12 +1156,8 @@ static void ib_sa_add_one(struct ib_device *device)
        int s, e, i;
        int count = 0;
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH)
-               s = e = 0;
-       else {
-               s = 1;
-               e = device->phys_port_cnt;
-       }
+       s = rdma_start_port(device);
+       e = rdma_end_port(device);
 
        sa_dev = kzalloc(sizeof *sa_dev +
                         (e - s + 1) * sizeof (struct ib_sa_port),
index 368a561d1a5d49d931ef45738c35f3be4b068725..f19b23817c2b49b3650f36077f00d67df801b3a7 100644 (file)
@@ -41,7 +41,7 @@
 #include "smi.h"
 #include "opa_smi.h"
 
-static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
+static enum smi_action __smi_handle_dr_smp_send(bool is_switch, int port_num,
                                                u8 *hop_ptr, u8 hop_cnt,
                                                const u8 *initial_path,
                                                const u8 *return_path,
@@ -64,7 +64,7 @@ static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
 
                /* C14-9:2 */
                if (*hop_ptr && *hop_ptr < hop_cnt) {
-                       if (node_type != RDMA_NODE_IB_SWITCH)
+                       if (!is_switch)
                                return IB_SMI_DISCARD;
 
                        /* return_path set when received */
@@ -77,7 +77,7 @@ static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
                if (*hop_ptr == hop_cnt) {
                        /* return_path set when received */
                        (*hop_ptr)++;
-                       return (node_type == RDMA_NODE_IB_SWITCH ||
+                       return (is_switch ||
                                dr_dlid_is_permissive ?
                                IB_SMI_HANDLE : IB_SMI_DISCARD);
                }
@@ -96,7 +96,7 @@ static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
 
                /* C14-13:2 */
                if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) {
-                       if (node_type != RDMA_NODE_IB_SWITCH)
+                       if (!is_switch)
                                return IB_SMI_DISCARD;
 
                        (*hop_ptr)--;
@@ -108,7 +108,7 @@ static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
                if (*hop_ptr == 1) {
                        (*hop_ptr)--;
                        /* C14-13:3 -- SMPs destined for SM shouldn't be here */
-                       return (node_type == RDMA_NODE_IB_SWITCH ||
+                       return (is_switch ||
                                dr_slid_is_permissive ?
                                IB_SMI_HANDLE : IB_SMI_DISCARD);
                }
@@ -127,9 +127,9 @@ static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
  * Return IB_SMI_DISCARD if the SMP should be discarded
  */
 enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
-                                      u8 node_type, int port_num)
+                                      bool is_switch, int port_num)
 {
-       return __smi_handle_dr_smp_send(node_type, port_num,
+       return __smi_handle_dr_smp_send(is_switch, port_num,
                                        &smp->hop_ptr, smp->hop_cnt,
                                        smp->initial_path,
                                        smp->return_path,
@@ -139,9 +139,9 @@ enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
 }
 
 enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp,
-                                      u8 node_type, int port_num)
+                                      bool is_switch, int port_num)
 {
-       return __smi_handle_dr_smp_send(node_type, port_num,
+       return __smi_handle_dr_smp_send(is_switch, port_num,
                                        &smp->hop_ptr, smp->hop_cnt,
                                        smp->route.dr.initial_path,
                                        smp->route.dr.return_path,
@@ -152,7 +152,7 @@ enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp,
                                        OPA_LID_PERMISSIVE);
 }
 
-static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
+static enum smi_action __smi_handle_dr_smp_recv(bool is_switch, int port_num,
                                                int phys_port_cnt,
                                                u8 *hop_ptr, u8 hop_cnt,
                                                const u8 *initial_path,
@@ -173,7 +173,7 @@ static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
 
                /* C14-9:2 -- intermediate hop */
                if (*hop_ptr && *hop_ptr < hop_cnt) {
-                       if (node_type != RDMA_NODE_IB_SWITCH)
+                       if (!is_switch)
                                return IB_SMI_DISCARD;
 
                        return_path[*hop_ptr] = port_num;
@@ -188,7 +188,7 @@ static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
                                return_path[*hop_ptr] = port_num;
                        /* hop_ptr updated when sending */
 
-                       return (node_type == RDMA_NODE_IB_SWITCH ||
+                       return (is_switch ||
                                dr_dlid_is_permissive ?
                                IB_SMI_HANDLE : IB_SMI_DISCARD);
                }
@@ -208,7 +208,7 @@ static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
 
                /* C14-13:2 */
                if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) {
-                       if (node_type != RDMA_NODE_IB_SWITCH)
+                       if (!is_switch)
                                return IB_SMI_DISCARD;
 
                        /* hop_ptr updated when sending */
@@ -224,8 +224,7 @@ static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
                                return IB_SMI_HANDLE;
                        }
                        /* hop_ptr updated when sending */
-                       return (node_type == RDMA_NODE_IB_SWITCH ?
-                               IB_SMI_HANDLE : IB_SMI_DISCARD);
+                       return (is_switch ? IB_SMI_HANDLE : IB_SMI_DISCARD);
                }
 
                /* C14-13:4 -- hop_ptr = 0 -> give to SM */
@@ -238,10 +237,10 @@ static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
  * Adjust information for a received SMP
  * Return IB_SMI_DISCARD if the SMP should be dropped
  */
-enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
+enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch,
                                       int port_num, int phys_port_cnt)
 {
-       return __smi_handle_dr_smp_recv(node_type, port_num, phys_port_cnt,
+       return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt,
                                        &smp->hop_ptr, smp->hop_cnt,
                                        smp->initial_path,
                                        smp->return_path,
@@ -254,10 +253,10 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
  * Adjust information for a received SMP
  * Return IB_SMI_DISCARD if the SMP should be dropped
  */
-enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, u8 node_type,
+enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch,
                                           int port_num, int phys_port_cnt)
 {
-       return __smi_handle_dr_smp_recv(node_type, port_num, phys_port_cnt,
+       return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt,
                                        &smp->hop_ptr, smp->hop_cnt,
                                        smp->route.dr.initial_path,
                                        smp->route.dr.return_path,
index aff96bac49b4c9e126a1e4b6fd309bc4b3b256aa..33c91c8a16e9524da0da6c00ed7a3259084f2c74 100644 (file)
@@ -51,12 +51,12 @@ enum smi_forward_action {
        IB_SMI_FORWARD  /* SMP should be forwarded (for switches only) */
 };
 
-enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
+enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch,
                                       int port_num, int phys_port_cnt);
 int smi_get_fwd_port(struct ib_smp *smp);
 extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp);
 extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
-                                             u8 node_type, int port_num);
+                                             bool is_switch, int port_num);
 
 /*
  * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
index ed6b6c85c334b124e3fa4a47225c3f8a6b5c62df..0b84a9cdfe5b90636d3633dbb42d84ef84c4e98e 100644 (file)
@@ -870,7 +870,7 @@ int ib_device_register_sysfs(struct ib_device *device,
                goto err_put;
        }
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH) {
+       if (rdma_cap_ib_switch(device)) {
                ret = add_port(device, 0, port_callback);
                if (ret)
                        goto err_put;
index 62c24b1452b89e2546f2e023a560ee3a21f222e4..00948107364466cafe28e95557be1fcf829e988c 100644 (file)
@@ -1193,6 +1193,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static DECLARE_BITMAP(overflow_map, IB_UCM_MAX_DEVICES);
 static void ib_ucm_release_dev(struct device *dev)
 {
        struct ib_ucm_device *ucm_dev;
@@ -1202,7 +1203,7 @@ static void ib_ucm_release_dev(struct device *dev)
        if (ucm_dev->devnum < IB_UCM_MAX_DEVICES)
                clear_bit(ucm_dev->devnum, dev_map);
        else
-               clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, dev_map);
+               clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, overflow_map);
        kfree(ucm_dev);
 }
 
@@ -1226,7 +1227,6 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
 
 static dev_t overflow_maj;
-static DECLARE_BITMAP(overflow_map, IB_UCM_MAX_DEVICES);
 static int find_overflow_devnum(void)
 {
        int ret;
index ad45469f7582dbe47788c5b1330803148c0b5dab..29b21213ea7586129357bd803c7de89096227bf1 100644 (file)
@@ -1354,10 +1354,10 @@ static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
        /* Acquire mutex's based on pointer comparison to prevent deadlock. */
        if (file1 < file2) {
                mutex_lock(&file1->mut);
-               mutex_lock(&file2->mut);
+               mutex_lock_nested(&file2->mut, SINGLE_DEPTH_NESTING);
        } else {
                mutex_lock(&file2->mut);
-               mutex_lock(&file1->mut);
+               mutex_lock_nested(&file1->mut, SINGLE_DEPTH_NESTING);
        }
 }
 
@@ -1616,6 +1616,7 @@ static void __exit ucma_cleanup(void)
        device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
        misc_deregister(&ucma_misc);
        idr_destroy(&ctx_idr);
+       idr_destroy(&multicast_idr);
 }
 
 module_init(ucma_init);
index b1b73232f21702161d7dc068f08e23e6759e04e8..bbbe0184e5922f6dab1fce7c56a92d1422da986e 100644 (file)
@@ -736,6 +736,10 @@ static struct ib_mr *iwch_get_dma_mr(struct ib_pd *pd, int acc)
        /*
         * T3 only supports 32 bits of size.
         */
+       if (sizeof(phys_addr_t) > 4) {
+               pr_warn_once(MOD "Cannot support dma_mrs on this platform.\n");
+               return ERR_PTR(-ENOTSUPP);
+       }
        bl.size = 0xffffffff;
        bl.addr = 0;
        kva = 0;
index c7aab48f07cdfcdebf3efb6374416619c9095e04..92d518382a9fce90c3e1dbae45034675072da274 100644 (file)
@@ -814,7 +814,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
                        printk(KERN_ERR MOD
                               "Unexpected cqe_status 0x%x for QPID=0x%0x\n",
                               CQE_STATUS(&cqe), CQE_QPID(&cqe));
-                       ret = -EINVAL;
+                       wc->status = IB_WC_FATAL_ERR;
                }
        }
 out:
index 12b5bc23832b13804c1f07b61ee4d83b8650dcd1..376b031c2c7fa0e00bee607ac3462c74e8d3594c 100644 (file)
@@ -226,8 +226,9 @@ int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
        if (!port_num || port_num > ibdev->phys_port_cnt || !in_wc)
                return IB_MAD_RESULT_FAILURE;
index 2d7e503d13cb5b9c2855936ce162f41d49ca0ced..871dbe56216a27e75ee64a1e4646ca027dd22a27 100644 (file)
@@ -31,6 +31,8 @@
  * SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/idr.h>
@@ -399,8 +401,8 @@ static int ipath_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        u32 bar0 = 0, bar1 = 0;
 
 #ifdef CONFIG_X86_64
-       if (WARN(pat_enabled(),
-                "ipath needs PAT disabled, boot with nopat kernel parameter\n")) {
+       if (pat_enabled()) {
+               pr_warn("ipath needs PAT disabled, boot with nopat kernel parameter\n");
                ret = -ENODEV;
                goto bail;
        }
index 948188e37f95ab3fc2dfb2dd4ab7a1698c0ae84f..ad3a926ab3c5d41b393ca04bee9a851ec196460c 100644 (file)
@@ -1499,8 +1499,9 @@ int ipath_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
        switch (in_mad->mad_hdr.mgmt_class) {
        case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
index 48253b839a6f741535c11a93cce685e2cce37901..30ba49c4a98c06b21dff0e0599569dfad19f1f17 100644 (file)
@@ -2044,9 +2044,9 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
 
        spin_lock_init(&idev->qp_table.lock);
        spin_lock_init(&idev->lk_table.lock);
-       idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE);
+       idev->sm_lid = be16_to_cpu(IB_LID_PERMISSIVE);
        /* Set the prefix to the default value (see ch. 4.1.1) */
-       idev->gid_prefix = __constant_cpu_to_be64(0xfe80000000000000ULL);
+       idev->gid_prefix = cpu_to_be64(0xfe80000000000000ULL);
 
        ret = ipath_init_qp_table(idev, ib_ipath_qp_table_size);
        if (ret)
index 85a50df2f20360e1b8da63959b49901843012198..68b3dfa922bf3e01ce3c00a60674ca508fd50912 100644 (file)
@@ -860,21 +860,31 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
        struct mlx4_ib_dev *dev = to_mdev(ibdev);
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
+       enum rdma_link_layer link = rdma_port_get_link_layer(ibdev, port_num);
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
-       switch (rdma_port_get_link_layer(ibdev, port_num)) {
-       case IB_LINK_LAYER_INFINIBAND:
-               if (!mlx4_is_slave(dev->dev))
-                       return ib_process_mad(ibdev, mad_flags, port_num, in_wc,
-                                             in_grh, in_mad, out_mad);
-       case IB_LINK_LAYER_ETHERNET:
-               return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
-                                         in_grh, in_mad, out_mad);
-       default:
-               return -EINVAL;
+       /* iboe_process_mad() which uses the HCA flow-counters to implement IB PMA
+        * queries, should be called only by VFs and for that specific purpose
+        */
+       if (link == IB_LINK_LAYER_INFINIBAND) {
+               if (mlx4_is_slave(dev->dev) &&
+                   in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
+                   in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS)
+                       return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
+                                               in_grh, in_mad, out_mad);
+
+               return ib_process_mad(ibdev, mad_flags, port_num, in_wc,
+                                     in_grh, in_mad, out_mad);
        }
+
+       if (link == IB_LINK_LAYER_ETHERNET)
+               return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
+                                       in_grh, in_mad, out_mad);
+
+       return -EINVAL;
 }
 
 static void send_handler(struct ib_mad_agent *agent,
index 067a691ecbed449e098d333e8d82cf62c47ebd7a..8be6db81646049a741abebe1c4ab982fad7e6011 100644 (file)
@@ -253,14 +253,15 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
        props->hca_core_clock = dev->dev->caps.hca_core_clock * 1000UL;
        props->timestamp_mask = 0xFFFFFFFFFFFFULL;
 
-       err = mlx4_get_internal_clock_params(dev->dev, &clock_params);
-       if (err)
-               goto out;
+       if (!mlx4_is_slave(dev->dev))
+               err = mlx4_get_internal_clock_params(dev->dev, &clock_params);
 
        if (uhw->outlen >= resp.response_length + sizeof(resp.hca_core_clock_offset)) {
-               resp.hca_core_clock_offset = clock_params.offset % PAGE_SIZE;
                resp.response_length += sizeof(resp.hca_core_clock_offset);
-               resp.comp_mask |= QUERY_DEVICE_RESP_MASK_TIMESTAMP;
+               if (!err && !mlx4_is_slave(dev->dev)) {
+                       resp.comp_mask |= QUERY_DEVICE_RESP_MASK_TIMESTAMP;
+                       resp.hca_core_clock_offset = clock_params.offset % PAGE_SIZE;
+               }
        }
 
        if (uhw->outlen) {
@@ -2669,31 +2670,33 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
        dm = kcalloc(ports, sizeof(*dm), GFP_ATOMIC);
        if (!dm) {
                pr_err("failed to allocate memory for tunneling qp update\n");
-               goto out;
+               return;
        }
 
        for (i = 0; i < ports; i++) {
                dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC);
                if (!dm[i]) {
                        pr_err("failed to allocate memory for tunneling qp update work struct\n");
-                       for (i = 0; i < dev->caps.num_ports; i++) {
-                               if (dm[i])
-                                       kfree(dm[i]);
-                       }
+                       while (--i >= 0)
+                               kfree(dm[i]);
                        goto out;
                }
-       }
-       /* initialize or tear down tunnel QPs for the slave */
-       for (i = 0; i < ports; i++) {
                INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work);
                dm[i]->port = first_port + i + 1;
                dm[i]->slave = slave;
                dm[i]->do_init = do_init;
                dm[i]->dev = ibdev;
-               spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags);
-               if (!ibdev->sriov.is_going_down)
+       }
+       /* initialize or tear down tunnel QPs for the slave */
+       spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags);
+       if (!ibdev->sriov.is_going_down) {
+               for (i = 0; i < ports; i++)
                        queue_work(ibdev->sriov.demux[i].ud_wq, &dm[i]->work);
                spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
+       } else {
+               spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
+               for (i = 0; i < ports; i++)
+                       kfree(dm[i]);
        }
 out:
        kfree(dm);
index 01fc97db45d6e8e3b92f38b1f667627ea4f2a60c..b84d13a487cc04dcfbb501cfbd460c335bf91f8d 100644 (file)
@@ -68,8 +68,9 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
        slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
 
index 6b2418b74c99ab84345403afe9d310f04aa465e5..7c3f2fb44ba51d8f288221df7b4d316a56adab28 100644 (file)
@@ -209,8 +209,9 @@ int mthca_process_mad(struct ib_device *ibdev,
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
        /* Forward locally generated traps to the SM */
        if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP &&
index 9047af4299065f543252a29297fbd40e603531b3..8a3ad170d790cc336c08a527db314d859beefd6c 100644 (file)
@@ -1520,8 +1520,9 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
        int rc = arpindex;
        struct net_device *netdev;
        struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
+       __be32 dst_ipaddr = htonl(dst_ip);
 
-       rt = ip_route_output(&init_net, htonl(dst_ip), 0, 0, 0);
+       rt = ip_route_output(&init_net, dst_ipaddr, nesvnic->local_ipaddr, 0, 0);
        if (IS_ERR(rt)) {
                printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",
                       __func__, dst_ip);
@@ -1533,7 +1534,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
        else
                netdev = nesvnic->netdev;
 
-       neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, netdev);
+       neigh = dst_neigh_lookup(&rt->dst, &dst_ipaddr);
 
        rcu_read_lock();
        if (neigh) {
index 02120d340d50cffa62fa87bb31e4e22502d5e547..4713dd7ed76432b6d11b042e6dfd24c268f82325 100644 (file)
@@ -3861,7 +3861,7 @@ void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
                                (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
                                (((u32)mac_addr[4]) << 8)  | (u32)mac_addr[5]);
                cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
-                               (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]);
+                               (((u32)mac_addr[0]) << 8) | (u32)mac_addr[1]);
        } else {
                cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = 0;
                cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
index b396344fae16af33153f0625104d95c17f488a8d..6a36338593cd0a1c09b1ad67c1d7d57f856b0e93 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_H__
 #define __OCRDMA_H__
index 1554cca5712aafd5659d1cfb80bafff7095f67ca..430b1350fe96ecd1eb16a67f18c2bc3a8e6afa80 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_ABI_H__
 #define __OCRDMA_ABI_H__
index 4bafa15708d0fc4212587cb4dfd6fce7d3f3211b..44766fee1f4e2cacb2d971f7858ad6e3eb4c4875 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <net/neighbour.h>
 #include <net/netevent.h>
@@ -215,8 +230,9 @@ int ocrdma_process_mad(struct ib_device *ibdev,
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
        switch (in_mad->mad_hdr.mgmt_class) {
        case IB_MGMT_CLASS_PERF_MGMT:
index cf366fe03cb822580fe96b69e5873ad255a34632..04a30ae674739b87dc266194f68aa27271df653e 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_AH_H__
 #define __OCRDMA_AH_H__
index 47615ff33bc6a1fb8c0c703b9f975acc6afe79c2..aab391a15db429104f52765346455ba07efa424b 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) CNA Adapters.              *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/sched.h>
 #include <linux/interrupt.h>
index e905972fceb7d48ff882800390c1330367815caf..7ed885c1851e28740b81a0588493c0d0ca92bc42 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) CNA Adapters.              *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_HW_H__
 #define __OCRDMA_HW_H__
index 8a1398b253a2bec42f2d0032e0aa915ce747bfd9..b119a3413a155574ae1eb1bdd020bb7d77e42822 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/module.h>
 #include <linux/idr.h>
@@ -46,7 +61,7 @@
 MODULE_VERSION(OCRDMA_ROCE_DRV_VERSION);
 MODULE_DESCRIPTION(OCRDMA_ROCE_DRV_DESC " " OCRDMA_ROCE_DRV_VERSION);
 MODULE_AUTHOR("Emulex Corporation");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
 
 static LIST_HEAD(ocrdma_dev_list);
 static DEFINE_SPINLOCK(ocrdma_devlist_lock);
@@ -696,6 +711,7 @@ static void __exit ocrdma_exit_module(void)
        ocrdma_unregister_inet6addr_notifier();
        ocrdma_unregister_inetaddr_notifier();
        ocrdma_rem_debugfs();
+       idr_destroy(&ocrdma_dev_id);
 }
 
 module_init(ocrdma_init_module);
index 02ad0aee99afc0c5e9449c4f58353e57d38903f1..80006b24aa118e752f444383fc9f4f3c3bafb191 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_SLI_H__
 #define __OCRDMA_SLI_H__
index 48d7ef51aa0c209678e0ed4bbe97bc5ff9a881d5..69334e214571b94ae0305bc8c9821aa0e261b7fe 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2014 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <rdma/ib_addr.h>
 #include <rdma/ib_pma.h>
index 091edd68a8a34678e5283b2374c58274c84580b3..c9e58d04c7b8d15c15c5d8ae4205c87cc3be521c 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2014 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_STATS_H__
 #define __OCRDMA_STATS_H__
index 5bb61eb58f2c71859969d73ac6e326d4dafc51fd..bc84cd462ecf3208e8576ad1ba1084578ddb7c29 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #include <linux/dma-mapping.h>
 #include <rdma/ib_verbs.h>
index b15c608efa7b03c72a2eb44e1f7b8af919db13b0..eaccb2d3cb9ff52f51fe0bbba3334053d519d047 100644 (file)
@@ -1,21 +1,36 @@
-/*******************************************************************
- * This file is part of the Emulex RoCE Device Driver for          *
- * RoCE (RDMA over Converged Ethernet) adapters.                   *
- * Copyright (C) 2008-2012 Emulex. All rights reserved.            *
- * EMULEX and SLI are trademarks of Emulex.                        *
- * www.emulex.com                                                  *
- *                                                                 *
- * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of version 2 of the GNU General       *
- * Public License as published by the Free Software Foundation.    *
- * This program is distributed in the hope that it will be useful. *
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
- * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
- * more details, a copy of which can be found in the file COPYING  *
- * included with this package.                                     *
+/* This file is part of the Emulex RoCE Device Driver for
+ * RoCE (RDMA over Converged Ethernet) adapters.
+ * Copyright (C) 2012-2015 Emulex. All rights reserved.
+ * EMULEX and SLI are trademarks of Emulex.
+ * www.emulex.com
+ *
+ * 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 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.
+ *
+ * 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 HOLDER 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.
  *
  * Contact Information:
  * linux-drivers@emulex.com
@@ -23,7 +38,7 @@
  * Emulex
  * 3333 Susan Street
  * Costa Mesa, CA 92626
- *******************************************************************/
+ */
 
 #ifndef __OCRDMA_VERBS_H__
 #define __OCRDMA_VERBS_H__
index 05e3242d84425acd6229204e642084a4ce0f654d..9625e7c438e57749c12495799fb896ac293880fd 100644 (file)
@@ -2412,8 +2412,9 @@ int qib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port,
        const struct ib_mad *in_mad = (const struct ib_mad *)in;
        struct ib_mad *out_mad = (struct ib_mad *)out;
 
-       BUG_ON(in_mad_size != sizeof(*in_mad) ||
-              *out_mad_size != sizeof(*out_mad));
+       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
+                        *out_mad_size != sizeof(*out_mad)))
+               return IB_MAD_RESULT_FAILURE;
 
        switch (in_mad->mad_hdr.mgmt_class) {
        case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
index bd94b0a6e9e535f8d8b4a9e1fa1428e0696e2947..79859c4d43c9c572f4946a364b87fdc74acf40a3 100644 (file)
@@ -239,7 +239,7 @@ struct ipoib_cm_tx {
        struct net_device   *dev;
        struct ipoib_neigh  *neigh;
        struct ipoib_path   *path;
-       struct ipoib_cm_tx_buf *tx_ring;
+       struct ipoib_tx_buf *tx_ring;
        unsigned             tx_head;
        unsigned             tx_tail;
        unsigned long        flags;
@@ -504,6 +504,33 @@ int ipoib_mcast_stop_thread(struct net_device *dev);
 void ipoib_mcast_dev_down(struct net_device *dev);
 void ipoib_mcast_dev_flush(struct net_device *dev);
 
+int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req);
+void ipoib_dma_unmap_tx(struct ipoib_dev_priv *priv,
+                       struct ipoib_tx_buf *tx_req);
+
+static inline void ipoib_build_sge(struct ipoib_dev_priv *priv,
+                                  struct ipoib_tx_buf *tx_req)
+{
+       int i, off;
+       struct sk_buff *skb = tx_req->skb;
+       skb_frag_t *frags = skb_shinfo(skb)->frags;
+       int nr_frags = skb_shinfo(skb)->nr_frags;
+       u64 *mapping = tx_req->mapping;
+
+       if (skb_headlen(skb)) {
+               priv->tx_sge[0].addr         = mapping[0];
+               priv->tx_sge[0].length       = skb_headlen(skb);
+               off = 1;
+       } else
+               off = 0;
+
+       for (i = 0; i < nr_frags; ++i) {
+               priv->tx_sge[i + off].addr = mapping[i + off];
+               priv->tx_sge[i + off].length = skb_frag_size(&frags[i]);
+       }
+       priv->tx_wr.num_sge          = nr_frags + off;
+}
+
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
 struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev);
 int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter);
index cf32a778e7d0ccc0b6225d9c01442f5d2ec4cdb1..ee39be6ccfb0fdd9aa75ad408543e1f0b08ff1d4 100644 (file)
@@ -694,14 +694,12 @@ repost:
 static inline int post_send(struct ipoib_dev_priv *priv,
                            struct ipoib_cm_tx *tx,
                            unsigned int wr_id,
-                           u64 addr, int len)
+                           struct ipoib_tx_buf *tx_req)
 {
        struct ib_send_wr *bad_wr;
 
-       priv->tx_sge[0].addr          = addr;
-       priv->tx_sge[0].length        = len;
+       ipoib_build_sge(priv, tx_req);
 
-       priv->tx_wr.num_sge     = 1;
        priv->tx_wr.wr_id       = wr_id | IPOIB_OP_CM;
 
        return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
@@ -710,8 +708,7 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
-       struct ipoib_cm_tx_buf *tx_req;
-       u64 addr;
+       struct ipoib_tx_buf *tx_req;
        int rc;
 
        if (unlikely(skb->len > tx->mtu)) {
@@ -735,24 +732,21 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
         */
        tx_req = &tx->tx_ring[tx->tx_head & (ipoib_sendq_size - 1)];
        tx_req->skb = skb;
-       addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
-       if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
+
+       if (unlikely(ipoib_dma_map_tx(priv->ca, tx_req))) {
                ++dev->stats.tx_errors;
                dev_kfree_skb_any(skb);
                return;
        }
 
-       tx_req->mapping = addr;
-
        skb_orphan(skb);
        skb_dst_drop(skb);
 
-       rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
-                      addr, skb->len);
+       rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), tx_req);
        if (unlikely(rc)) {
                ipoib_warn(priv, "post_send failed, error %d\n", rc);
                ++dev->stats.tx_errors;
-               ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
+               ipoib_dma_unmap_tx(priv, tx_req);
                dev_kfree_skb_any(skb);
        } else {
                dev->trans_start = jiffies;
@@ -777,7 +771,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_cm_tx *tx = wc->qp->qp_context;
        unsigned int wr_id = wc->wr_id & ~IPOIB_OP_CM;
-       struct ipoib_cm_tx_buf *tx_req;
+       struct ipoib_tx_buf *tx_req;
        unsigned long flags;
 
        ipoib_dbg_data(priv, "cm send completion: id %d, status: %d\n",
@@ -791,7 +785,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 
        tx_req = &tx->tx_ring[wr_id];
 
-       ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE);
+       ipoib_dma_unmap_tx(priv, tx_req);
 
        /* FIXME: is this right? Shouldn't we only increment on success? */
        ++dev->stats.tx_packets;
@@ -1036,6 +1030,9 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
 
        struct ib_qp *tx_qp;
 
+       if (dev->features & NETIF_F_SG)
+               attr.cap.max_send_sge = MAX_SKB_FRAGS + 1;
+
        tx_qp = ib_create_qp(priv->pd, &attr);
        if (PTR_ERR(tx_qp) == -EINVAL) {
                ipoib_warn(priv, "can't use GFP_NOIO for QPs on device %s, using GFP_KERNEL\n",
@@ -1170,7 +1167,7 @@ err_tx:
 static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
 {
        struct ipoib_dev_priv *priv = netdev_priv(p->dev);
-       struct ipoib_cm_tx_buf *tx_req;
+       struct ipoib_tx_buf *tx_req;
        unsigned long begin;
 
        ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
@@ -1197,8 +1194,7 @@ timeout:
 
        while ((int) p->tx_tail - (int) p->tx_head < 0) {
                tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
-               ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
-                                   DMA_TO_DEVICE);
+               ipoib_dma_unmap_tx(priv, tx_req);
                dev_kfree_skb_any(tx_req->skb);
                ++p->tx_tail;
                netif_tx_lock_bh(p->dev);
@@ -1455,7 +1451,6 @@ static void ipoib_cm_stale_task(struct work_struct *work)
        spin_unlock_irq(&priv->lock);
 }
 
-
 static ssize_t show_mode(struct device *d, struct device_attribute *attr,
                         char *buf)
 {
index 63b92cbb29ad0ad1f0165a738a47efbe0f650e04..d266667ca9b82273dd4b7abb4856f69b29f65174 100644 (file)
@@ -263,8 +263,7 @@ repost:
                           "for buf %d\n", wr_id);
 }
 
-static int ipoib_dma_map_tx(struct ib_device *ca,
-                           struct ipoib_tx_buf *tx_req)
+int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req)
 {
        struct sk_buff *skb = tx_req->skb;
        u64 *mapping = tx_req->mapping;
@@ -305,8 +304,8 @@ partial_error:
        return -EIO;
 }
 
-static void ipoib_dma_unmap_tx(struct ib_device *ca,
-                              struct ipoib_tx_buf *tx_req)
+void ipoib_dma_unmap_tx(struct ipoib_dev_priv *priv,
+                       struct ipoib_tx_buf *tx_req)
 {
        struct sk_buff *skb = tx_req->skb;
        u64 *mapping = tx_req->mapping;
@@ -314,7 +313,8 @@ static void ipoib_dma_unmap_tx(struct ib_device *ca,
        int off;
 
        if (skb_headlen(skb)) {
-               ib_dma_unmap_single(ca, mapping[0], skb_headlen(skb), DMA_TO_DEVICE);
+               ib_dma_unmap_single(priv->ca, mapping[0], skb_headlen(skb),
+                                   DMA_TO_DEVICE);
                off = 1;
        } else
                off = 0;
@@ -322,8 +322,8 @@ static void ipoib_dma_unmap_tx(struct ib_device *ca,
        for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
-               ib_dma_unmap_page(ca, mapping[i + off], skb_frag_size(frag),
-                                 DMA_TO_DEVICE);
+               ib_dma_unmap_page(priv->ca, mapping[i + off],
+                                 skb_frag_size(frag), DMA_TO_DEVICE);
        }
 }
 
@@ -389,7 +389,7 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 
        tx_req = &priv->tx_ring[wr_id];
 
-       ipoib_dma_unmap_tx(priv->ca, tx_req);
+       ipoib_dma_unmap_tx(priv, tx_req);
 
        ++dev->stats.tx_packets;
        dev->stats.tx_bytes += tx_req->skb->len;
@@ -514,24 +514,10 @@ static inline int post_send(struct ipoib_dev_priv *priv,
                            void *head, int hlen)
 {
        struct ib_send_wr *bad_wr;
-       int i, off;
        struct sk_buff *skb = tx_req->skb;
-       skb_frag_t *frags = skb_shinfo(skb)->frags;
-       int nr_frags = skb_shinfo(skb)->nr_frags;
-       u64 *mapping = tx_req->mapping;
 
-       if (skb_headlen(skb)) {
-               priv->tx_sge[0].addr         = mapping[0];
-               priv->tx_sge[0].length       = skb_headlen(skb);
-               off = 1;
-       } else
-               off = 0;
+       ipoib_build_sge(priv, tx_req);
 
-       for (i = 0; i < nr_frags; ++i) {
-               priv->tx_sge[i + off].addr = mapping[i + off];
-               priv->tx_sge[i + off].length = skb_frag_size(&frags[i]);
-       }
-       priv->tx_wr.num_sge          = nr_frags + off;
        priv->tx_wr.wr_id            = wr_id;
        priv->tx_wr.wr.ud.remote_qpn = qpn;
        priv->tx_wr.wr.ud.ah         = address;
@@ -617,7 +603,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
                ipoib_warn(priv, "post_send failed, error %d\n", rc);
                ++dev->stats.tx_errors;
                --priv->tx_outstanding;
-               ipoib_dma_unmap_tx(priv->ca, tx_req);
+               ipoib_dma_unmap_tx(priv, tx_req);
                dev_kfree_skb_any(skb);
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
@@ -868,7 +854,7 @@ int ipoib_ib_dev_stop(struct net_device *dev)
                        while ((int) priv->tx_tail - (int) priv->tx_head < 0) {
                                tx_req = &priv->tx_ring[priv->tx_tail &
                                                        (ipoib_sendq_size - 1)];
-                               ipoib_dma_unmap_tx(priv->ca, tx_req);
+                               ipoib_dma_unmap_tx(priv, tx_req);
                                dev_kfree_skb_any(tx_req->skb);
                                ++priv->tx_tail;
                                --priv->tx_outstanding;
@@ -985,20 +971,21 @@ static inline int update_child_pkey(struct ipoib_dev_priv *priv)
 }
 
 static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
-                               enum ipoib_flush_level level)
+                               enum ipoib_flush_level level,
+                               int nesting)
 {
        struct ipoib_dev_priv *cpriv;
        struct net_device *dev = priv->dev;
        int result;
 
-       down_read(&priv->vlan_rwsem);
+       down_read_nested(&priv->vlan_rwsem, nesting);
 
        /*
         * Flush any child interfaces too -- they might be up even if
         * the parent is down.
         */
        list_for_each_entry(cpriv, &priv->child_intfs, list)
-               __ipoib_ib_dev_flush(cpriv, level);
+               __ipoib_ib_dev_flush(cpriv, level, nesting + 1);
 
        up_read(&priv->vlan_rwsem);
 
@@ -1076,7 +1063,7 @@ void ipoib_ib_dev_flush_light(struct work_struct *work)
        struct ipoib_dev_priv *priv =
                container_of(work, struct ipoib_dev_priv, flush_light);
 
-       __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_LIGHT);
+       __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_LIGHT, 0);
 }
 
 void ipoib_ib_dev_flush_normal(struct work_struct *work)
@@ -1084,7 +1071,7 @@ void ipoib_ib_dev_flush_normal(struct work_struct *work)
        struct ipoib_dev_priv *priv =
                container_of(work, struct ipoib_dev_priv, flush_normal);
 
-       __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_NORMAL);
+       __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_NORMAL, 0);
 }
 
 void ipoib_ib_dev_flush_heavy(struct work_struct *work)
@@ -1092,7 +1079,7 @@ void ipoib_ib_dev_flush_heavy(struct work_struct *work)
        struct ipoib_dev_priv *priv =
                container_of(work, struct ipoib_dev_priv, flush_heavy);
 
-       __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_HEAVY);
+       __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_HEAVY, 0);
 }
 
 void ipoib_ib_dev_cleanup(struct net_device *dev)
index da149c278cb8149a7541169c7b05147be82f8ed5..b2943c84a5dda0aecdd8904917f2ebbb02b9b013 100644 (file)
@@ -190,7 +190,7 @@ static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_featu
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
        if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags))
-               features &= ~(NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+               features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
 
        return features;
 }
@@ -232,6 +232,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
                ipoib_warn(priv, "enabling connected mode "
                           "will cause multicast packet drops\n");
                netdev_update_features(dev);
+               dev_set_mtu(dev, ipoib_cm_max_mtu(dev));
                rtnl_unlock();
                priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
 
@@ -1577,7 +1578,8 @@ static struct net_device *ipoib_add_port(const char *format,
        SET_NETDEV_DEV(priv->dev, hca->dma_device);
        priv->dev->dev_id = port - 1;
 
-       if (!ib_query_port(hca, port, &attr))
+       result = ib_query_port(hca, port, &attr);
+       if (!result)
                priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu);
        else {
                printk(KERN_WARNING "%s: ib_query_port %d failed\n",
@@ -1598,7 +1600,8 @@ static struct net_device *ipoib_add_port(const char *format,
                goto device_init_failed;
        }
 
-       if (ipoib_set_dev_features(priv, hca))
+       result = ipoib_set_dev_features(priv, hca);
+       if (result)
                goto device_init_failed;
 
        /*
@@ -1684,7 +1687,7 @@ static void ipoib_add_one(struct ib_device *device)
        struct list_head *dev_list;
        struct net_device *dev;
        struct ipoib_dev_priv *priv;
-       int s, e, p;
+       int p;
        int count = 0;
 
        dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
@@ -1693,15 +1696,7 @@ static void ipoib_add_one(struct ib_device *device)
 
        INIT_LIST_HEAD(dev_list);
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH) {
-               s = 0;
-               e = 0;
-       } else {
-               s = 1;
-               e = device->phys_port_cnt;
-       }
-
-       for (p = s; p <= e; ++p) {
+       for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
                if (!rdma_protocol_ib(device, p))
                        continue;
                dev = ipoib_add_port("ib%d", device, p);
index 9e6ee82a8fd76f490de93d6117754e2a6657ec72..851c8219d50104105ec8d97a3ba743cb6f59626b 100644 (file)
@@ -177,7 +177,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
                else
                        size += ipoib_recvq_size * ipoib_max_conn_qp;
        } else
-               goto out_free_wq;
+               if (ret != -ENOSYS)
+                       goto out_free_wq;
 
        cq_attr.cqe = size;
        priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL,
index 7717009631271ea6965a7d60b9dcf3f74acdd1d6..d851e1828d6f5152e9c8ca49de9b64a3b953f180 100644 (file)
@@ -775,6 +775,17 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        ret = isert_rdma_post_recvl(isert_conn);
        if (ret)
                goto out_conn_dev;
+       /*
+        * Obtain the second reference now before isert_rdma_accept() to
+        * ensure that any initiator generated REJECT CM event that occurs
+        * asynchronously won't drop the last reference until the error path
+        * in iscsi_target_login_sess_out() does it's ->iscsit_free_conn() ->
+        * isert_free_conn() -> isert_put_conn() -> kref_put().
+        */
+       if (!kref_get_unless_zero(&isert_conn->kref)) {
+               isert_warn("conn %p connect_release is running\n", isert_conn);
+               goto out_conn_dev;
+       }
 
        ret = isert_rdma_accept(isert_conn);
        if (ret)
@@ -836,11 +847,6 @@ isert_connected_handler(struct rdma_cm_id *cma_id)
 
        isert_info("conn %p\n", isert_conn);
 
-       if (!kref_get_unless_zero(&isert_conn->kref)) {
-               isert_warn("conn %p connect_release is running\n", isert_conn);
-               return;
-       }
-
        mutex_lock(&isert_conn->mutex);
        if (isert_conn->state != ISER_CONN_FULL_FEATURE)
                isert_conn->state = ISER_CONN_UP;
index 267dc4f7550236e89fae58ff80c4a3953cff877f..31a20b462266611299aeeae5cd51fd19b69b635e 100644 (file)
@@ -161,13 +161,10 @@ static int srp_tmo_set(const char *val, const struct kernel_param *kp)
 {
        int tmo, res;
 
-       if (strncmp(val, "off", 3) != 0) {
-               res = kstrtoint(val, 0, &tmo);
-               if (res)
-                       goto out;
-       } else {
-               tmo = -1;
-       }
+       res = srp_parse_tmo(&tmo, val);
+       if (res)
+               goto out;
+
        if (kp->arg == &srp_reconnect_delay)
                res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo,
                                    srp_dev_loss_tmo);
@@ -3379,7 +3376,7 @@ static void srp_add_one(struct ib_device *device)
        struct srp_device *srp_dev;
        struct ib_device_attr *dev_attr;
        struct srp_host *host;
-       int mr_page_shift, s, e, p;
+       int mr_page_shift, p;
        u64 max_pages_per_mr;
 
        dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
@@ -3443,15 +3440,7 @@ static void srp_add_one(struct ib_device *device)
        if (IS_ERR(srp_dev->mr))
                goto err_pd;
 
-       if (device->node_type == RDMA_NODE_IB_SWITCH) {
-               s = 0;
-               e = 0;
-       } else {
-               s = 1;
-               e = device->phys_port_cnt;
-       }
-
-       for (p = s; p <= e; ++p) {
+       for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) {
                host = srp_add_port(srp_dev, p);
                if (host)
                        list_add_tail(&host->list, &srp_dev->dev_list);
index 82897ca17f32349df3e3cc332b9b0204bbc524a3..60ff0a2390e5f02f7cffabb9a5154cc0c4b734e7 100644 (file)
@@ -302,7 +302,7 @@ static void srpt_get_iou(struct ib_dm_mad *mad)
        int i;
 
        ioui = (struct ib_dm_iou_info *)mad->data;
-       ioui->change_id = __constant_cpu_to_be16(1);
+       ioui->change_id = cpu_to_be16(1);
        ioui->max_controllers = 16;
 
        /* set present for slot 1 and empty for the rest */
@@ -330,13 +330,13 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot,
 
        if (!slot || slot > 16) {
                mad->mad_hdr.status
-                       = __constant_cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD);
+                       = cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD);
                return;
        }
 
        if (slot > 2) {
                mad->mad_hdr.status
-                       = __constant_cpu_to_be16(DM_MAD_STATUS_NO_IOC);
+                       = cpu_to_be16(DM_MAD_STATUS_NO_IOC);
                return;
        }
 
@@ -348,10 +348,10 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot,
        iocp->device_version = cpu_to_be16(sdev->dev_attr.hw_ver);
        iocp->subsys_vendor_id = cpu_to_be32(sdev->dev_attr.vendor_id);
        iocp->subsys_device_id = 0x0;
-       iocp->io_class = __constant_cpu_to_be16(SRP_REV16A_IB_IO_CLASS);
-       iocp->io_subclass = __constant_cpu_to_be16(SRP_IO_SUBCLASS);
-       iocp->protocol = __constant_cpu_to_be16(SRP_PROTOCOL);
-       iocp->protocol_version = __constant_cpu_to_be16(SRP_PROTOCOL_VERSION);
+       iocp->io_class = cpu_to_be16(SRP_REV16A_IB_IO_CLASS);
+       iocp->io_subclass = cpu_to_be16(SRP_IO_SUBCLASS);
+       iocp->protocol = cpu_to_be16(SRP_PROTOCOL);
+       iocp->protocol_version = cpu_to_be16(SRP_PROTOCOL_VERSION);
        iocp->send_queue_depth = cpu_to_be16(sdev->srq_size);
        iocp->rdma_read_depth = 4;
        iocp->send_size = cpu_to_be32(srp_max_req_size);
@@ -379,13 +379,13 @@ static void srpt_get_svc_entries(u64 ioc_guid,
 
        if (!slot || slot > 16) {
                mad->mad_hdr.status
-                       = __constant_cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD);
+                       = cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD);
                return;
        }
 
        if (slot > 2 || lo > hi || hi > 1) {
                mad->mad_hdr.status
-                       = __constant_cpu_to_be16(DM_MAD_STATUS_NO_IOC);
+                       = cpu_to_be16(DM_MAD_STATUS_NO_IOC);
                return;
        }
 
@@ -436,7 +436,7 @@ static void srpt_mgmt_method_get(struct srpt_port *sp, struct ib_mad *rq_mad,
                break;
        default:
                rsp_mad->mad_hdr.status =
-                   __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR);
+                   cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR);
                break;
        }
 }
@@ -493,11 +493,11 @@ static void srpt_mad_recv_handler(struct ib_mad_agent *mad_agent,
                break;
        case IB_MGMT_METHOD_SET:
                dm_mad->mad_hdr.status =
-                   __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR);
+                   cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR);
                break;
        default:
                dm_mad->mad_hdr.status =
-                   __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD);
+                   cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD);
                break;
        }
 
@@ -1535,7 +1535,7 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch,
        memset(srp_rsp, 0, sizeof *srp_rsp);
        srp_rsp->opcode = SRP_RSP;
        srp_rsp->req_lim_delta =
-               __constant_cpu_to_be32(1 + atomic_xchg(&ch->req_lim_delta, 0));
+               cpu_to_be32(1 + atomic_xchg(&ch->req_lim_delta, 0));
        srp_rsp->tag = tag;
        srp_rsp->status = status;
 
@@ -1585,8 +1585,8 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
        memset(srp_rsp, 0, sizeof *srp_rsp);
 
        srp_rsp->opcode = SRP_RSP;
-       srp_rsp->req_lim_delta = __constant_cpu_to_be32(1
-                                   + atomic_xchg(&ch->req_lim_delta, 0));
+       srp_rsp->req_lim_delta =
+               cpu_to_be32(1 + atomic_xchg(&ch->req_lim_delta, 0));
        srp_rsp->tag = tag;
 
        srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
@@ -1630,7 +1630,7 @@ static uint64_t srpt_unpack_lun(const uint8_t *lun, int len)
        switch (len) {
        case 8:
                if ((*((__be64 *)lun) &
-                    __constant_cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
+                    cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
                        goto out_err;
                break;
        case 4:
@@ -2449,8 +2449,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
        }
 
        if (it_iu_len > srp_max_req_size || it_iu_len < 64) {
-               rej->reason = __constant_cpu_to_be32(
-                               SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE);
                ret = -EINVAL;
                pr_err("rejected SRP_LOGIN_REQ because its"
                       " length (%d bytes) is out of range (%d .. %d)\n",
@@ -2459,8 +2459,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
        }
 
        if (!sport->enabled) {
-               rej->reason = __constant_cpu_to_be32(
-                            SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
                ret = -EINVAL;
                pr_err("rejected SRP_LOGIN_REQ because the target port"
                       " has not yet been enabled\n");
@@ -2505,8 +2505,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
        if (*(__be64 *)req->target_port_id != cpu_to_be64(srpt_service_guid)
            || *(__be64 *)(req->target_port_id + 8) !=
               cpu_to_be64(srpt_service_guid)) {
-               rej->reason = __constant_cpu_to_be32(
-                               SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL);
                ret = -ENOMEM;
                pr_err("rejected SRP_LOGIN_REQ because it"
                       " has an invalid target port identifier.\n");
@@ -2515,8 +2515,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
 
        ch = kzalloc(sizeof *ch, GFP_KERNEL);
        if (!ch) {
-               rej->reason = __constant_cpu_to_be32(
-                                       SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
                pr_err("rejected SRP_LOGIN_REQ because no memory.\n");
                ret = -ENOMEM;
                goto reject;
@@ -2552,8 +2552,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
 
        ret = srpt_create_ch_ib(ch);
        if (ret) {
-               rej->reason = __constant_cpu_to_be32(
-                               SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
                pr_err("rejected SRP_LOGIN_REQ because creating"
                       " a new RDMA channel failed.\n");
                goto free_ring;
@@ -2561,8 +2561,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
 
        ret = srpt_ch_qp_rtr(ch, ch->qp);
        if (ret) {
-               rej->reason = __constant_cpu_to_be32(
-                               SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
                pr_err("rejected SRP_LOGIN_REQ because enabling"
                       " RTR failed (error code = %d)\n", ret);
                goto destroy_ib;
@@ -2580,15 +2579,15 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
        if (!nacl) {
                pr_info("Rejected login because no ACL has been"
                        " configured yet for initiator %s.\n", ch->sess_name);
-               rej->reason = __constant_cpu_to_be32(
-                               SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
                goto destroy_ib;
        }
 
        ch->sess = transport_init_session(TARGET_PROT_NORMAL);
        if (IS_ERR(ch->sess)) {
-               rej->reason = __constant_cpu_to_be32(
-                               SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+               rej->reason = cpu_to_be32(
+                             SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
                pr_debug("Failed to create session\n");
                goto deregister_session;
        }
@@ -2604,8 +2603,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
        rsp->max_it_iu_len = req->req_it_iu_len;
        rsp->max_ti_iu_len = req->req_it_iu_len;
        ch->max_ti_iu_len = it_iu_len;
-       rsp->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT
-                                             | SRP_BUF_FORMAT_INDIRECT);
+       rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT
+                                  | SRP_BUF_FORMAT_INDIRECT);
        rsp->req_lim_delta = cpu_to_be32(ch->rq_size);
        atomic_set(&ch->req_lim, ch->rq_size);
        atomic_set(&ch->req_lim_delta, 0);
@@ -2655,8 +2654,8 @@ free_ch:
 reject:
        rej->opcode = SRP_LOGIN_REJ;
        rej->tag = req->tag;
-       rej->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT
-                                             | SRP_BUF_FORMAT_INDIRECT);
+       rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT
+                                  | SRP_BUF_FORMAT_INDIRECT);
 
        ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
                             (void *)rej, sizeof *rej);
index 074a65ed17bb4d595d2b48f13e0d2e03c2267bc6..766bf26601163c37aebf265160b4d3d0ce09617f 100644 (file)
@@ -71,6 +71,18 @@ static void input_leds_event(struct input_handle *handle, unsigned int type,
 {
 }
 
+static int input_leds_get_count(struct input_dev *dev)
+{
+       unsigned int led_code;
+       int count = 0;
+
+       for_each_set_bit(led_code, dev->ledbit, LED_CNT)
+               if (input_led_info[led_code].name)
+                       count++;
+
+       return count;
+}
+
 static int input_leds_connect(struct input_handler *handler,
                              struct input_dev *dev,
                              const struct input_device_id *id)
@@ -81,7 +93,7 @@ static int input_leds_connect(struct input_handler *handler,
        int led_no;
        int error;
 
-       num_leds = bitmap_weight(dev->ledbit, LED_CNT);
+       num_leds = input_leds_get_count(dev);
        if (!num_leds)
                return -ENXIO;
 
@@ -112,7 +124,7 @@ static int input_leds_connect(struct input_handler *handler,
                led->handle = &leds->handle;
                led->code = led_code;
 
-               if (WARN_ON(!input_led_info[led_code].name))
+               if (!input_led_info[led_code].name)
                        continue;
 
                led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
index 27b6a3ce18caf2e996177e6c313fff2b21a4ad19..891797ad76bccda3ae132e1fc59483b539e522ee 100644 (file)
@@ -196,7 +196,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
                if (n_buttons[i] < 1)
                        continue;
 
-               if (n_buttons[i] > 6) {
+               if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
                        printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
                        err = -EINVAL;
                        goto err_unreg_devs;
index 097d7216d98ee4e4d394726e9d4c9743067d14f8..c6dc644aa5806b37cb4e0dcbbc6217d915e8a562 100644 (file)
@@ -246,7 +246,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                 * convert it to descriptor.
                 */
                if (!button->gpiod && gpio_is_valid(button->gpio)) {
-                       unsigned flags = 0;
+                       unsigned flags = GPIOF_IN;
 
                        if (button->active_low)
                                flags |= GPIOF_ACTIVE_LOW;
index 10e140af5aac1a9ea309d2b237af065cc7abf684..1ac898db303afe84edd003a03129eb0f27518837 100644 (file)
@@ -292,3 +292,4 @@ module_platform_driver(axp20x_pek_driver);
 MODULE_DESCRIPTION("axp20x Power Button");
 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:axp20x-pek");
index fc17b9592f5435238d980cc30d266a4ee399415a..10c4e3d462f112f15ec9843093c5f988d44780b9 100644 (file)
@@ -183,7 +183,8 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
        if (pdata && pdata->coexist)
                return true;
 
-       if (of_find_node_by_name(node, "codec")) {
+       node = of_find_node_by_name(node, "codec");
+       if (node) {
                of_node_put(node);
                return true;
        }
index 113d6f1516a54956f74635f7eb51231ab5490052..4d246861d692b810f3074aa7917cda86893ac6c2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/dmi.h>
 
 #include "psmouse.h"
 #include "alps.h"
@@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
 #define ALPS_FOUR_BUTTONS      0x40    /* 4 direction button present */
 #define ALPS_PS2_INTERLEAVED   0x80    /* 3-byte PS/2 packet interleaved with
                                           6-byte ALPS packet */
+#define ALPS_DELL              0x100   /* device is a Dell laptop */
 #define ALPS_BUTTONPAD         0x200   /* device is a clickpad */
 
 static const struct alps_model_info alps_model_data[] = {
@@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
                return;
        }
 
-       /* Non interleaved V2 dualpoint has separate stick button bits */
+       /* Dell non interleaved V2 dualpoint has separate stick button bits */
        if (priv->proto_version == ALPS_PROTO_V2 &&
-           priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) {
+           priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) {
                left |= packet[0] & 1;
                right |= packet[0] & 2;
                middle |= packet[0] & 4;
@@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
        priv->byte0 = protocol->byte0;
        priv->mask0 = protocol->mask0;
        priv->flags = protocol->flags;
+       if (dmi_name_in_vendors("Dell"))
+               priv->flags |= ALPS_DELL;
 
        priv->x_max = 2000;
        priv->y_max = 1400;
index b10709f0461559c4d5ca03f47ae1d82c75663e91..30e3442518f85cfe06732e0f331962458396008c 100644 (file)
@@ -2,6 +2,7 @@
  * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
  *
  * Copyright (C) 2008     Henrik Rydberg (rydberg@euromail.se)
+ * Copyright (C) 2015      John Horan (knasher@gmail.com)
  *
  * The USB initialization and package decoding was made by
  * Scott Shawcroft as part of the touchd user-space driver project:
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
+/* MacbookPro12,1 (2015) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI   0x0272
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO    0x0273
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS    0x0274
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -152,6 +157,10 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
+       /* MacbookPro12,1 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
        /* Terminating entry */
        {}
 };
@@ -180,21 +189,47 @@ struct bt_data {
 enum tp_type {
        TYPE1,                  /* plain trackpad */
        TYPE2,                  /* button integrated in trackpad */
-       TYPE3                   /* additional header fields since June 2013 */
+       TYPE3,                  /* additional header fields since June 2013 */
+       TYPE4                   /* additional header field for pressure data */
 };
 
 /* trackpad finger data offsets, le16-aligned */
-#define FINGER_TYPE1           (13 * sizeof(__le16))
-#define FINGER_TYPE2           (15 * sizeof(__le16))
-#define FINGER_TYPE3           (19 * sizeof(__le16))
+#define HEADER_TYPE1           (13 * sizeof(__le16))
+#define HEADER_TYPE2           (15 * sizeof(__le16))
+#define HEADER_TYPE3           (19 * sizeof(__le16))
+#define HEADER_TYPE4           (23 * sizeof(__le16))
 
 /* trackpad button data offsets */
+#define BUTTON_TYPE1           0
 #define BUTTON_TYPE2           15
 #define BUTTON_TYPE3           23
+#define BUTTON_TYPE4           31
 
 /* list of device capability bits */
 #define HAS_INTEGRATED_BUTTON  1
 
+/* trackpad finger data block size */
+#define FSIZE_TYPE1            (14 * sizeof(__le16))
+#define FSIZE_TYPE2            (14 * sizeof(__le16))
+#define FSIZE_TYPE3            (14 * sizeof(__le16))
+#define FSIZE_TYPE4            (15 * sizeof(__le16))
+
+/* offset from header to finger struct */
+#define DELTA_TYPE1            (0 * sizeof(__le16))
+#define DELTA_TYPE2            (0 * sizeof(__le16))
+#define DELTA_TYPE3            (0 * sizeof(__le16))
+#define DELTA_TYPE4            (1 * sizeof(__le16))
+
+/* usb control message mode switch data */
+#define USBMSG_TYPE1           8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE2           8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE3           8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE4           2, 0x302, 2, 1, 0x1, 0x0
+
+/* Wellspring initialization constants */
+#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID                1
+#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID       9
+
 /* trackpad finger structure, le16-aligned */
 struct tp_finger {
        __le16 origin;          /* zero when switching track finger */
@@ -207,14 +242,13 @@ struct tp_finger {
        __le16 orientation;     /* 16384 when point, else 15 bit angle */
        __le16 touch_major;     /* touch area, major axis */
        __le16 touch_minor;     /* touch area, minor axis */
-       __le16 unused[3];       /* zeros */
+       __le16 unused[2];       /* zeros */
+       __le16 pressure;        /* pressure on forcetouch touchpad */
        __le16 multi;           /* one finger: varies, more fingers: constant */
 } __attribute__((packed,aligned(2)));
 
 /* trackpad finger data size, empirically at least ten fingers */
 #define MAX_FINGERS            16
-#define SIZEOF_FINGER          sizeof(struct tp_finger)
-#define SIZEOF_ALL_FINGERS     (MAX_FINGERS * SIZEOF_FINGER)
 #define MAX_FINGER_ORIENTATION 16384
 
 /* device-specific parameters */
@@ -232,8 +266,17 @@ struct bcm5974_config {
        int bt_datalen;         /* data length of the button interface */
        int tp_ep;              /* the endpoint of the trackpad interface */
        enum tp_type tp_type;   /* type of trackpad interface */
-       int tp_offset;          /* offset to trackpad finger data */
+       int tp_header;          /* bytes in header block */
        int tp_datalen;         /* data length of the trackpad interface */
+       int tp_button;          /* offset to button data */
+       int tp_fsize;           /* bytes in single finger block */
+       int tp_delta;           /* offset from header to finger struct */
+       int um_size;            /* usb control message length */
+       int um_req_val;         /* usb control message value */
+       int um_req_idx;         /* usb control message index */
+       int um_switch_idx;      /* usb control message mode switch index */
+       int um_switch_on;       /* usb control message mode switch on */
+       int um_switch_off;      /* usb control message mode switch off */
        struct bcm5974_param p; /* finger pressure limits */
        struct bcm5974_param w; /* finger width limits */
        struct bcm5974_param x; /* horizontal limits */
@@ -259,6 +302,24 @@ struct bcm5974 {
        int slots[MAX_FINGERS];                         /* slot assignments */
 };
 
+/* trackpad finger block data, le16-aligned */
+static const struct tp_finger *get_tp_finger(const struct bcm5974 *dev, int i)
+{
+       const struct bcm5974_config *c = &dev->cfg;
+       u8 *f_base = dev->tp_data + c->tp_header + c->tp_delta;
+
+       return (const struct tp_finger *)(f_base + i * c->tp_fsize);
+}
+
+#define DATAFORMAT(type)                               \
+       type,                                           \
+       HEADER_##type,                                  \
+       HEADER_##type + (MAX_FINGERS) * (FSIZE_##type), \
+       BUTTON_##type,                                  \
+       FSIZE_##type,                                   \
+       DELTA_##type,                                   \
+       USBMSG_##type
+
 /* logical signal quality */
 #define SN_PRESSURE    45              /* pressure signal-to-noise ratio */
 #define SN_WIDTH       25              /* width signal-to-noise ratio */
@@ -273,7 +334,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
                0,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE1),
                { SN_PRESSURE, 0, 256 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4824, 5342 },
@@ -286,7 +347,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
                0,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE1),
                { SN_PRESSURE, 0, 256 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4824, 4824 },
@@ -299,7 +360,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING3_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4460, 5166 },
@@ -312,7 +373,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
@@ -325,7 +386,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4616, 5112 },
@@ -338,7 +399,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4415, 5050 },
@@ -351,7 +412,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
@@ -364,7 +425,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4750, 5280 },
@@ -377,7 +438,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
@@ -390,7 +451,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4750, 5280 },
@@ -403,7 +464,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
                HAS_INTEGRATED_BUTTON,
                0x84, sizeof(struct bt_data),
-               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               0x81, DATAFORMAT(TYPE2),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4750, 5280 },
@@ -416,13 +477,26 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
                HAS_INTEGRATED_BUTTON,
                0, sizeof(struct bt_data),
-               0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
+               0x83, DATAFORMAT(TYPE3),
                { SN_PRESSURE, 0, 300 },
                { SN_WIDTH, 0, 2048 },
                { SN_COORD, -4620, 5140 },
                { SN_COORD, -150, 6600 },
                { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING9_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING9_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0, sizeof(struct bt_data),
+               0x83, DATAFORMAT(TYPE4),
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -4828, 5345 },
+               { SN_COORD, -203, 6803 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+       },
        {}
 };
 
@@ -549,19 +623,18 @@ static int report_tp_state(struct bcm5974 *dev, int size)
        struct input_dev *input = dev->input;
        int raw_n, i, n = 0;
 
-       if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
+       if (size < c->tp_header || (size - c->tp_header) % c->tp_fsize != 0)
                return -EIO;
 
-       /* finger data, le16-aligned */
-       f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
-       raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
+       raw_n = (size - c->tp_header) / c->tp_fsize;
 
        for (i = 0; i < raw_n; i++) {
-               if (raw2int(f[i].touch_major) == 0)
+               f = get_tp_finger(dev, i);
+               if (raw2int(f->touch_major) == 0)
                        continue;
-               dev->pos[n].x = raw2int(f[i].abs_x);
-               dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
-               dev->index[n++] = &f[i];
+               dev->pos[n].x = raw2int(f->abs_x);
+               dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
+               dev->index[n++] = f;
        }
 
        input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
@@ -572,32 +645,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
 
        input_mt_sync_frame(input);
 
-       report_synaptics_data(input, c, f, raw_n);
+       report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
 
-       /* type 2 reports button events via ibt only */
-       if (c->tp_type == TYPE2) {
-               int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
+       /* later types report button events via integrated button only */
+       if (c->caps & HAS_INTEGRATED_BUTTON) {
+               int ibt = raw2int(dev->tp_data[c->tp_button]);
                input_report_key(input, BTN_LEFT, ibt);
        }
 
-       if (c->tp_type == TYPE3)
-               input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]);
-
        input_sync(input);
 
        return 0;
 }
 
-/* Wellspring initialization constants */
-#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID                1
-#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID       9
-#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE          0x300
-#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX          0
-#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE           0x01
-#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE           0x08
-
 static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
 {
+       const struct bcm5974_config *c = &dev->cfg;
        int retval = 0, size;
        char *data;
 
@@ -605,7 +668,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
        if (dev->cfg.tp_type == TYPE3)
                return 0;
 
-       data = kmalloc(8, GFP_KERNEL);
+       data = kmalloc(c->um_size, GFP_KERNEL);
        if (!data) {
                dev_err(&dev->intf->dev, "out of memory\n");
                retval = -ENOMEM;
@@ -616,28 +679,24 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
        size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                        BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+                       c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
 
-       if (size != 8) {
+       if (size != c->um_size) {
                dev_err(&dev->intf->dev, "could not read from device\n");
                retval = -EIO;
                goto out;
        }
 
        /* apply the mode switch */
-       data[0] = on ?
-               BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
-               BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
+       data[c->um_switch_idx] = on ? c->um_switch_on : c->um_switch_off;
 
        /* write configuration */
        size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                        BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
                        USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
-                       BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+                       c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
 
-       if (size != 8) {
+       if (size != c->um_size) {
                dev_err(&dev->intf->dev, "could not write to device\n");
                retval = -EIO;
                goto out;
index 62641f2adaf74d2a3e5ba2473ac00b9a8984cb28..5b5f403d8ce6a80a3c458e6537ee0baedf38073e 100644 (file)
@@ -771,7 +771,7 @@ static const struct attribute_group *elan_sysfs_groups[] = {
  */
 static void elan_report_contact(struct elan_tp_data *data,
                                int contact_num, bool contact_valid,
-                               bool hover_event, u8 *finger_data)
+                               u8 *finger_data)
 {
        struct input_dev *input = data->input;
        unsigned int pos_x, pos_y;
@@ -815,9 +815,7 @@ static void elan_report_contact(struct elan_tp_data *data,
                input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
                input_report_abs(input, ABS_MT_POSITION_X, pos_x);
                input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y);
-               input_report_abs(input, ABS_MT_DISTANCE, hover_event);
-               input_report_abs(input, ABS_MT_PRESSURE,
-                                hover_event ? 0 : scaled_pressure);
+               input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure);
                input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
                input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
                input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
@@ -839,14 +837,14 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
        hover_event = hover_info & 0x40;
        for (i = 0; i < ETP_MAX_FINGERS; i++) {
                contact_valid = tp_info & (1U << (3 + i));
-               elan_report_contact(data, i, contact_valid, hover_event,
-                                   finger_data);
+               elan_report_contact(data, i, contact_valid, finger_data);
 
                if (contact_valid)
                        finger_data += ETP_FINGER_DATA_LEN;
        }
 
        input_report_key(input, BTN_LEFT, tp_info & 0x01);
+       input_report_abs(input, ABS_DISTANCE, hover_event != 0);
        input_mt_report_pointer_emulation(input, true);
        input_sync(input);
 }
@@ -922,6 +920,7 @@ static int elan_setup_input_device(struct elan_tp_data *data)
        input_abs_set_res(input, ABS_Y, data->y_res);
        input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
        input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
+       input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
 
        /* And MT parameters */
        input_set_abs_params(input, ABS_MT_POSITION_X, 0, data->max_x, 0, 0);
@@ -934,7 +933,6 @@ static int elan_setup_input_device(struct elan_tp_data *data)
                             ETP_FINGER_WIDTH * max_width, 0, 0);
        input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
                             ETP_FINGER_WIDTH * min_width, 0, 0);
-       input_set_abs_params(input, ABS_MT_DISTANCE, 0, 1, 0, 0);
 
        data->input = input;
 
index ce3d40004458c87392339472f654462fae7cf0bc..2955f1d0ca6c4c9137f786028ca36bff706beab2 100644 (file)
@@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
        struct elantech_data *etd = psmouse->private;
        unsigned char *packet = psmouse->packet;
        unsigned char packet_type = packet[3] & 0x03;
+       unsigned int ic_version;
        bool sanity_check;
 
        if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
                return PACKET_TRACKPOINT;
 
+       /* This represents the version of IC body. */
+       ic_version = (etd->fw_version & 0x0f0000) >> 16;
+
        /*
         * Sanity check based on the constant bits of a packet.
         * The constant bits change depending on the value of
-        * the hardware flag 'crc_enabled' but are the same for
-        * every packet, regardless of the type.
+        * the hardware flag 'crc_enabled' and the version of
+        * the IC body, but are the same for every packet,
+        * regardless of the type.
         */
        if (etd->crc_enabled)
                sanity_check = ((packet[3] & 0x08) == 0x00);
+       else if (ic_version == 7 && etd->samples[1] == 0x2A)
+               sanity_check = ((packet[3] & 0x1c) == 0x10);
        else
                sanity_check = ((packet[0] & 0x0c) == 0x04 &&
                                (packet[3] & 0x1c) == 0x10);
@@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
  * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
+ * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
@@ -1167,7 +1175,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
        struct input_dev *dev = psmouse->dev;
        struct elantech_data *etd = psmouse->private;
        unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
-       unsigned int x_res = 0, y_res = 0;
+       unsigned int x_res = 31, y_res = 31;
 
        if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
                return -1;
@@ -1232,8 +1240,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                /* For X to recognize me as touchpad. */
                input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
                input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
-               input_abs_set_res(dev, ABS_X, x_res);
-               input_abs_set_res(dev, ABS_Y, y_res);
                /*
                 * range of pressure and width is the same as v2,
                 * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
@@ -1246,8 +1252,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
                input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
                input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
-               input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
-               input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
                input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
                                     ETP_PMAX_V2, 0, 0);
                /*
@@ -1259,6 +1263,13 @@ static int elantech_set_input_params(struct psmouse *psmouse)
                break;
        }
 
+       input_abs_set_res(dev, ABS_X, x_res);
+       input_abs_set_res(dev, ABS_Y, y_res);
+       if (etd->hw_version > 1) {
+               input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
+               input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
+       }
+
        etd->y_max = y_max;
        etd->width = width;
 
@@ -1648,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse)
                     etd->capabilities[0], etd->capabilities[1],
                     etd->capabilities[2]);
 
+       if (etd->hw_version != 1) {
+               if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
+                       psmouse_err(psmouse, "failed to query sample data\n");
+                       goto init_fail;
+               }
+               psmouse_info(psmouse,
+                            "Elan sample query result %02x, %02x, %02x\n",
+                            etd->samples[0], etd->samples[1], etd->samples[2]);
+       }
+
        if (elantech_set_absolute_mode(psmouse)) {
                psmouse_err(psmouse,
                            "failed to put touchpad into absolute mode.\n");
index f965d1569cc338059cdd540bad44ed927c6ddc3e..e1cbf409d9c8d0d4e7d21e13d57851ae6565b535 100644 (file)
@@ -129,6 +129,7 @@ struct elantech_data {
        unsigned char reg_26;
        unsigned char debug;
        unsigned char capabilities[3];
+       unsigned char samples[3];
        bool paritycheck;
        bool jumpy_cursor;
        bool reports_pressure;
index 35c8d0ceabeebf989b8eeff5cd54ee8f3ac2e247..6025eb430c0a5010c908961ccf8897943fd3c945 100644 (file)
@@ -1199,7 +1199,7 @@ static void set_input_params(struct psmouse *psmouse,
                                        ABS_MT_POSITION_Y);
                /* Image sensors can report per-contact pressure */
                input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
-               input_mt_init_slots(dev, 3, INPUT_MT_POINTER | INPUT_MT_TRACK);
+               input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK);
 
                /* Image sensors can signal 4 and 5 finger clicks */
                __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
@@ -1484,12 +1484,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
        priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
 
        psmouse_info(psmouse,
-                    "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
+                    "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
                     SYN_ID_MODEL(priv->identity),
                     SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
                     priv->model_id,
                     priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
-                    priv->board_id, priv->firmware_id);
+                    priv->ext_cap_10, priv->board_id, priv->firmware_id);
 
        set_input_params(psmouse, priv);
 
index b4d12e29abff72008125c2406b3808cf174e0f71..e36162b28c2aae268166c2e735e318b793b9dfa8 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/dmi.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
@@ -34,6 +35,7 @@ struct goodix_ts_data {
        int abs_y_max;
        unsigned int max_touch_num;
        unsigned int int_trigger_type;
+       bool rotated_screen;
 };
 
 #define GOODIX_MAX_HEIGHT              4096
@@ -60,6 +62,30 @@ static const unsigned long goodix_irq_flags[] = {
        IRQ_TYPE_LEVEL_HIGH,
 };
 
+/*
+ * Those tablets have their coordinates origin at the bottom right
+ * of the tablet, as if rotated 180 degrees
+ */
+static const struct dmi_system_id rotated_screen[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               .ident = "WinBook TW100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
+               }
+       },
+       {
+               .ident = "WinBook TW700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
+               },
+       },
+#endif
+       {}
+};
+
 /**
  * goodix_i2c_read - read data from a register of the i2c slave device.
  *
@@ -129,6 +155,11 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
        int input_y = get_unaligned_le16(&coor_data[3]);
        int input_w = get_unaligned_le16(&coor_data[5]);
 
+       if (ts->rotated_screen) {
+               input_x = ts->abs_x_max - input_x;
+               input_y = ts->abs_y_max - input_y;
+       }
+
        input_mt_slot(ts->input_dev, id);
        input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
        input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
@@ -223,6 +254,11 @@ static void goodix_read_config(struct goodix_ts_data *ts)
                ts->abs_y_max = GOODIX_MAX_HEIGHT;
                ts->max_touch_num = GOODIX_MAX_CONTACTS;
        }
+
+       ts->rotated_screen = dmi_check_system(rotated_screen);
+       if (ts->rotated_screen)
+               dev_dbg(&ts->client->dev,
+                        "Applying '180 degrees rotated screen' quirk\n");
 }
 
 /**
index f2c6c352c55af2d3bb4dbf243516b19b9c62a65a..2c41107240dec274e5ec34724a882d87189f0103 100644 (file)
@@ -627,6 +627,9 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
                goto err_out;
        }
 
+       /* TSC-25 data sheet specifies a delay after the RESET command */
+       msleep(150);
+
        /* set coordinate output rate */
        buf[0] = buf[1] = 0xFF;
        ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
index a57e9b7498953bb9ebf947695caea46d73e2bfeb..658ee39e65696898422bcd9c825d8a49fbc37359 100644 (file)
@@ -76,8 +76,6 @@ LIST_HEAD(hpet_map);
  * Domain for untranslated devices - only allocated
  * if iommu=pt passed on kernel cmd line.
  */
-static struct protection_domain *pt_domain;
-
 static const struct iommu_ops amd_iommu_ops;
 
 static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
@@ -96,7 +94,7 @@ struct iommu_dev_data {
        struct protection_domain *domain; /* Domain the device is bound to */
        u16 devid;                        /* PCI Device ID */
        bool iommu_v2;                    /* Device can make use of IOMMUv2 */
-       bool passthrough;                 /* Default for device is pt_domain */
+       bool passthrough;                 /* Device is identity mapped */
        struct {
                bool enabled;
                int qdep;
@@ -116,7 +114,6 @@ struct iommu_cmd {
 struct kmem_cache *amd_iommu_irq_cache;
 
 static void update_domain(struct protection_domain *domain);
-static int alloc_passthrough_domain(void);
 static int protection_domain_init(struct protection_domain *domain);
 
 /****************************************************************************
@@ -2167,15 +2164,17 @@ static int attach_device(struct device *dev,
        dev_data = get_dev_data(dev);
 
        if (domain->flags & PD_IOMMUV2_MASK) {
-               if (!dev_data->iommu_v2 || !dev_data->passthrough)
+               if (!dev_data->passthrough)
                        return -EINVAL;
 
-               if (pdev_iommuv2_enable(pdev) != 0)
-                       return -EINVAL;
+               if (dev_data->iommu_v2) {
+                       if (pdev_iommuv2_enable(pdev) != 0)
+                               return -EINVAL;
 
-               dev_data->ats.enabled = true;
-               dev_data->ats.qdep    = pci_ats_queue_depth(pdev);
-               dev_data->pri_tlp     = pci_pri_tlp_required(pdev);
+                       dev_data->ats.enabled = true;
+                       dev_data->ats.qdep    = pci_ats_queue_depth(pdev);
+                       dev_data->pri_tlp     = pci_pri_tlp_required(pdev);
+               }
        } else if (amd_iommu_iotlb_sup &&
                   pci_enable_ats(pdev, PAGE_SHIFT) == 0) {
                dev_data->ats.enabled = true;
@@ -2221,15 +2220,6 @@ static void __detach_device(struct iommu_dev_data *dev_data)
        do_detach(head);
 
        spin_unlock_irqrestore(&domain->lock, flags);
-
-       /*
-        * If we run in passthrough mode the device must be assigned to the
-        * passthrough domain if it is detached from any other domain.
-        * Make sure we can deassign from the pt_domain itself.
-        */
-       if (dev_data->passthrough &&
-           (dev_data->domain == NULL && domain != pt_domain))
-               __attach_device(dev_data, pt_domain);
 }
 
 /*
@@ -2249,7 +2239,7 @@ static void detach_device(struct device *dev)
        __detach_device(dev_data);
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
 
-       if (domain->flags & PD_IOMMUV2_MASK)
+       if (domain->flags & PD_IOMMUV2_MASK && dev_data->iommu_v2)
                pdev_iommuv2_disable(to_pci_dev(dev));
        else if (dev_data->ats.enabled)
                pci_disable_ats(to_pci_dev(dev));
@@ -2287,17 +2277,15 @@ static int amd_iommu_add_device(struct device *dev)
 
        BUG_ON(!dev_data);
 
-       if (dev_data->iommu_v2)
+       if (iommu_pass_through || dev_data->iommu_v2)
                iommu_request_dm_for_dev(dev);
 
        /* Domains are initialized for this device - have a look what we ended up with */
        domain = iommu_get_domain_for_dev(dev);
-       if (domain->type == IOMMU_DOMAIN_IDENTITY) {
+       if (domain->type == IOMMU_DOMAIN_IDENTITY)
                dev_data->passthrough = true;
-               dev->archdata.dma_ops = &nommu_dma_ops;
-       } else {
+       else
                dev->archdata.dma_ops = &amd_iommu_dma_ops;
-       }
 
 out:
        iommu_completion_wait(iommu);
@@ -2862,8 +2850,17 @@ int __init amd_iommu_init_api(void)
 
 int __init amd_iommu_init_dma_ops(void)
 {
+       swiotlb        = iommu_pass_through ? 1 : 0;
        iommu_detected = 1;
-       swiotlb = 0;
+
+       /*
+        * In case we don't initialize SWIOTLB (actually the common case
+        * when AMD IOMMU is enabled), make sure there are global
+        * dma_ops set as a fall-back for devices not handled by this
+        * driver (for example non-PCI devices).
+        */
+       if (!swiotlb)
+               dma_ops = &nommu_dma_ops;
 
        amd_iommu_stats_init();
 
@@ -2947,21 +2944,6 @@ out_err:
        return NULL;
 }
 
-static int alloc_passthrough_domain(void)
-{
-       if (pt_domain != NULL)
-               return 0;
-
-       /* allocate passthrough domain */
-       pt_domain = protection_domain_alloc();
-       if (!pt_domain)
-               return -ENOMEM;
-
-       pt_domain->mode = PAGE_MODE_NONE;
-
-       return 0;
-}
-
 static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 {
        struct protection_domain *pdomain;
@@ -3222,33 +3204,6 @@ static const struct iommu_ops amd_iommu_ops = {
  *
  *****************************************************************************/
 
-int __init amd_iommu_init_passthrough(void)
-{
-       struct iommu_dev_data *dev_data;
-       struct pci_dev *dev = NULL;
-       int ret;
-
-       ret = alloc_passthrough_domain();
-       if (ret)
-               return ret;
-
-       for_each_pci_dev(dev) {
-               if (!check_device(&dev->dev))
-                       continue;
-
-               dev_data = get_dev_data(&dev->dev);
-               dev_data->passthrough = true;
-
-               attach_device(&dev->dev, pt_domain);
-       }
-
-       amd_iommu_stats_init();
-
-       pr_info("AMD-Vi: Initialized for Passthrough Mode\n");
-
-       return 0;
-}
-
 /* IOMMUv2 specific functions */
 int amd_iommu_register_ppr_notifier(struct notifier_block *nb)
 {
@@ -3363,7 +3318,12 @@ static int __flush_pasid(struct protection_domain *domain, int pasid,
                struct amd_iommu *iommu;
                int qdep;
 
-               BUG_ON(!dev_data->ats.enabled);
+               /*
+                  There might be non-IOMMUv2 capable devices in an IOMMUv2
+                * domain.
+                */
+               if (!dev_data->ats.enabled)
+                       continue;
 
                qdep  = dev_data->ats.qdep;
                iommu = amd_iommu_rlookup_table[dev_data->devid];
index dbda9ae68c5d70fff7926e39a2ef506b7165bf65..a24495eb4e26c5c596efa79c084b14c19fe5932c 100644 (file)
@@ -2026,14 +2026,6 @@ static bool detect_ivrs(void)
        return true;
 }
 
-static int amd_iommu_init_dma(void)
-{
-       if (iommu_pass_through)
-               return amd_iommu_init_passthrough();
-       else
-               return amd_iommu_init_dma_ops();
-}
-
 /****************************************************************************
  *
  * AMD IOMMU Initialization State Machine
@@ -2073,7 +2065,7 @@ static int __init state_next(void)
                init_state = ret ? IOMMU_INIT_ERROR : IOMMU_INTERRUPTS_EN;
                break;
        case IOMMU_INTERRUPTS_EN:
-               ret = amd_iommu_init_dma();
+               ret = amd_iommu_init_dma_ops();
                init_state = ret ? IOMMU_INIT_ERROR : IOMMU_DMA_OPS;
                break;
        case IOMMU_DMA_OPS:
index 3465faf1809e4cb1d6630e5cdc8f87cd4e405bd2..f7b875bb70d42138027f49ebde8150d27ce14cd2 100644 (file)
@@ -132,11 +132,19 @@ static struct device_state *get_device_state(u16 devid)
 
 static void free_device_state(struct device_state *dev_state)
 {
+       struct iommu_group *group;
+
        /*
         * First detach device from domain - No more PRI requests will arrive
         * from that device after it is unbound from the IOMMUv2 domain.
         */
-       iommu_detach_device(dev_state->domain, &dev_state->pdev->dev);
+       group = iommu_group_get(&dev_state->pdev->dev);
+       if (WARN_ON(!group))
+               return;
+
+       iommu_detach_group(dev_state->domain, group);
+
+       iommu_group_put(group);
 
        /* Everything is down now, free the IOMMUv2 domain */
        iommu_domain_free(dev_state->domain);
@@ -731,6 +739,7 @@ EXPORT_SYMBOL(amd_iommu_unbind_pasid);
 int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 {
        struct device_state *dev_state;
+       struct iommu_group *group;
        unsigned long flags;
        int ret, tmp;
        u16 devid;
@@ -776,10 +785,16 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
        if (ret)
                goto out_free_domain;
 
-       ret = iommu_attach_device(dev_state->domain, &pdev->dev);
-       if (ret != 0)
+       group = iommu_group_get(&pdev->dev);
+       if (!group)
                goto out_free_domain;
 
+       ret = iommu_attach_group(dev_state->domain, group);
+       if (ret != 0)
+               goto out_drop_group;
+
+       iommu_group_put(group);
+
        spin_lock_irqsave(&state_lock, flags);
 
        if (__get_device_state(devid) != NULL) {
@@ -794,6 +809,9 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids)
 
        return 0;
 
+out_drop_group:
+       iommu_group_put(group);
+
 out_free_domain:
        iommu_domain_free(dev_state->domain);
 
index 8e9ec81ce4bbd85473d6d6a35e7c3567569187ee..da902baaa7946aac569b7ebe8a316c647dfd8187 100644 (file)
  * Stream table.
  *
  * Linear: Enough to cover 1 << IDR1.SIDSIZE entries
- * 2lvl: 8k L1 entries, 256 lazy entries per table (each table covers a PCI bus)
+ * 2lvl: 128k L1 entries,
+ *       256 lazy entries per table (each table covers a PCI bus)
  */
-#define STRTAB_L1_SZ_SHIFT             16
+#define STRTAB_L1_SZ_SHIFT             20
 #define STRTAB_SPLIT                   8
 
 #define STRTAB_L1_DESC_DWORDS          1
 #define ARM64_TCR_TG0_SHIFT            14
 #define ARM64_TCR_TG0_MASK             0x3UL
 #define CTXDESC_CD_0_TCR_IRGN0_SHIFT   8
-#define ARM64_TCR_IRGN0_SHIFT          24
+#define ARM64_TCR_IRGN0_SHIFT          8
 #define ARM64_TCR_IRGN0_MASK           0x3UL
 #define CTXDESC_CD_0_TCR_ORGN0_SHIFT   10
-#define ARM64_TCR_ORGN0_SHIFT          26
+#define ARM64_TCR_ORGN0_SHIFT          10
 #define ARM64_TCR_ORGN0_MASK           0x3UL
 #define CTXDESC_CD_0_TCR_SH0_SHIFT     12
 #define ARM64_TCR_SH0_SHIFT            12
@@ -542,6 +543,9 @@ struct arm_smmu_device {
 #define ARM_SMMU_FEAT_HYP              (1 << 12)
        u32                             features;
 
+#define ARM_SMMU_OPT_SKIP_PREFETCH     (1 << 0)
+       u32                             options;
+
        struct arm_smmu_cmdq            cmdq;
        struct arm_smmu_evtq            evtq;
        struct arm_smmu_priq            priq;
@@ -602,11 +606,35 @@ struct arm_smmu_domain {
 static DEFINE_SPINLOCK(arm_smmu_devices_lock);
 static LIST_HEAD(arm_smmu_devices);
 
+struct arm_smmu_option_prop {
+       u32 opt;
+       const char *prop;
+};
+
+static struct arm_smmu_option_prop arm_smmu_options[] = {
+       { ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" },
+       { 0, NULL},
+};
+
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
        return container_of(dom, struct arm_smmu_domain, domain);
 }
 
+static void parse_driver_options(struct arm_smmu_device *smmu)
+{
+       int i = 0;
+
+       do {
+               if (of_property_read_bool(smmu->dev->of_node,
+                                               arm_smmu_options[i].prop)) {
+                       smmu->options |= arm_smmu_options[i].opt;
+                       dev_notice(smmu->dev, "option %s\n",
+                               arm_smmu_options[i].prop);
+               }
+       } while (arm_smmu_options[++i].opt);
+}
+
 /* Low-level queue manipulation functions */
 static bool queue_full(struct arm_smmu_queue *q)
 {
@@ -1036,7 +1064,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
        arm_smmu_sync_ste_for_sid(smmu, sid);
 
        /* It's likely that we'll want to use the new STE soon */
-       arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
+       if (!(smmu->options & ARM_SMMU_OPT_SKIP_PREFETCH))
+               arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
 }
 
 static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
@@ -1064,7 +1093,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
                return 0;
 
        size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
-       strtab = &cfg->strtab[sid >> STRTAB_SPLIT << STRTAB_L1_DESC_DWORDS];
+       strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
 
        desc->span = STRTAB_SPLIT + 1;
        desc->l2ptr = dma_zalloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
@@ -2020,21 +2049,23 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
 {
        void *strtab;
        u64 reg;
-       u32 size;
+       u32 size, l1size;
        int ret;
        struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
 
        /* Calculate the L1 size, capped to the SIDSIZE */
        size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
        size = min(size, smmu->sid_bits - STRTAB_SPLIT);
-       if (size + STRTAB_SPLIT < smmu->sid_bits)
+       cfg->num_l1_ents = 1 << size;
+
+       size += STRTAB_SPLIT;
+       if (size < smmu->sid_bits)
                dev_warn(smmu->dev,
                         "2-level strtab only covers %u/%u bits of SID\n",
-                        size + STRTAB_SPLIT, smmu->sid_bits);
+                        size, smmu->sid_bits);
 
-       cfg->num_l1_ents = 1 << size;
-       size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
-       strtab = dma_zalloc_coherent(smmu->dev, size, &cfg->strtab_dma,
+       l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
+       strtab = dma_zalloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
                                     GFP_KERNEL);
        if (!strtab) {
                dev_err(smmu->dev,
@@ -2055,8 +2086,7 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
        ret = arm_smmu_init_l1_strtab(smmu);
        if (ret)
                dma_free_coherent(smmu->dev,
-                                 cfg->num_l1_ents *
-                                 (STRTAB_L1_DESC_DWORDS << 3),
+                                 l1size,
                                  strtab,
                                  cfg->strtab_dma);
        return ret;
@@ -2573,6 +2603,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        if (irq > 0)
                smmu->gerr_irq = irq;
 
+       parse_driver_options(smmu);
+
        /* Probe the h/w */
        ret = arm_smmu_device_probe(smmu);
        if (ret)
index a98a7b27aca1dec2cb2f53319df8a49abcf8e645..0649b94f59584ca5b885cd0ecad595a84af0d89d 100644 (file)
@@ -1830,8 +1830,9 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
 
 static void domain_exit(struct dmar_domain *domain)
 {
+       struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
        struct page *freelist = NULL;
-       int i;
 
        /* Domain 0 is reserved, so dont process it */
        if (!domain)
@@ -1851,8 +1852,10 @@ static void domain_exit(struct dmar_domain *domain)
 
        /* clear attached or cached domains */
        rcu_read_lock();
-       for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus)
-               iommu_detach_domain(domain, g_iommus[i]);
+       for_each_active_iommu(iommu, drhd)
+               if (domain_type_is_vm(domain) ||
+                   test_bit(iommu->seq_id, domain->iommu_bmp))
+                       iommu_detach_domain(domain, iommu);
        rcu_read_unlock();
 
        dma_free_pagelist(freelist);
index 692fe2bc81979b6b48f984ec6d88c117fbfdebdd..c12bb93334ff99e7a5ddc72d274b00c4eeb9c24c 100644 (file)
@@ -68,7 +68,9 @@ static struct irq_chip crossbar_chip = {
        .irq_mask               = irq_chip_mask_parent,
        .irq_unmask             = irq_chip_unmask_parent,
        .irq_retrigger          = irq_chip_retrigger_hierarchy,
-       .irq_set_wake           = irq_chip_set_wake_parent,
+       .irq_set_type           = irq_chip_set_type_parent,
+       .flags                  = IRQCHIP_MASK_ON_SUSPEND |
+                                 IRQCHIP_SKIP_SET_WAKE,
 #ifdef CONFIG_SMP
        .irq_set_affinity       = irq_chip_set_affinity_parent,
 #endif
index 1b7e155869f6c1a5f9ff361f246b6fd71539dadc..c00e2db351ba5aec327ebb1e98085b25b9b4d056 100644 (file)
@@ -75,6 +75,13 @@ struct its_node {
 
 #define ITS_ITT_ALIGN          SZ_256
 
+struct event_lpi_map {
+       unsigned long           *lpi_map;
+       u16                     *col_map;
+       irq_hw_number_t         lpi_base;
+       int                     nr_lpis;
+};
+
 /*
  * The ITS view of a device - belongs to an ITS, a collection, owns an
  * interrupt translation table, and a list of interrupts.
@@ -82,11 +89,8 @@ struct its_node {
 struct its_device {
        struct list_head        entry;
        struct its_node         *its;
-       struct its_collection   *collection;
+       struct event_lpi_map    event_map;
        void                    *itt;
-       unsigned long           *lpi_map;
-       irq_hw_number_t         lpi_base;
-       int                     nr_lpis;
        u32                     nr_ites;
        u32                     device_id;
 };
@@ -99,6 +103,14 @@ static struct rdists *gic_rdists;
 #define gic_data_rdist()               (raw_cpu_ptr(gic_rdists->rdist))
 #define gic_data_rdist_rd_base()       (gic_data_rdist()->rd_base)
 
+static struct its_collection *dev_event_to_col(struct its_device *its_dev,
+                                              u32 event)
+{
+       struct its_node *its = its_dev->its;
+
+       return its->collections + its_dev->event_map.col_map[event];
+}
+
 /*
  * ITS command descriptors - parameters to be encoded in a command
  * block.
@@ -134,7 +146,7 @@ struct its_cmd_desc {
                struct {
                        struct its_device *dev;
                        struct its_collection *col;
-                       u32 id;
+                       u32 event_id;
                } its_movi_cmd;
 
                struct {
@@ -241,7 +253,7 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
 
        its_fixup_cmd(cmd);
 
-       return desc->its_mapd_cmd.dev->collection;
+       return NULL;
 }
 
 static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
@@ -260,52 +272,72 @@ static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
 static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
+       struct its_collection *col;
+
+       col = dev_event_to_col(desc->its_mapvi_cmd.dev,
+                              desc->its_mapvi_cmd.event_id);
+
        its_encode_cmd(cmd, GITS_CMD_MAPVI);
        its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id);
        its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id);
        its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id);
-       its_encode_collection(cmd, desc->its_mapvi_cmd.dev->collection->col_id);
+       its_encode_collection(cmd, col->col_id);
 
        its_fixup_cmd(cmd);
 
-       return desc->its_mapvi_cmd.dev->collection;
+       return col;
 }
 
 static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
                                                 struct its_cmd_desc *desc)
 {
+       struct its_collection *col;
+
+       col = dev_event_to_col(desc->its_movi_cmd.dev,
+                              desc->its_movi_cmd.event_id);
+
        its_encode_cmd(cmd, GITS_CMD_MOVI);
        its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id);
-       its_encode_event_id(cmd, desc->its_movi_cmd.id);
+       its_encode_event_id(cmd, desc->its_movi_cmd.event_id);
        its_encode_collection(cmd, desc->its_movi_cmd.col->col_id);
 
        its_fixup_cmd(cmd);
 
-       return desc->its_movi_cmd.dev->collection;
+       return col;
 }
 
 static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
                                                    struct its_cmd_desc *desc)
 {
+       struct its_collection *col;
+
+       col = dev_event_to_col(desc->its_discard_cmd.dev,
+                              desc->its_discard_cmd.event_id);
+
        its_encode_cmd(cmd, GITS_CMD_DISCARD);
        its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id);
        its_encode_event_id(cmd, desc->its_discard_cmd.event_id);
 
        its_fixup_cmd(cmd);
 
-       return desc->its_discard_cmd.dev->collection;
+       return col;
 }
 
 static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
                                                struct its_cmd_desc *desc)
 {
+       struct its_collection *col;
+
+       col = dev_event_to_col(desc->its_inv_cmd.dev,
+                              desc->its_inv_cmd.event_id);
+
        its_encode_cmd(cmd, GITS_CMD_INV);
        its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
        its_encode_event_id(cmd, desc->its_inv_cmd.event_id);
 
        its_fixup_cmd(cmd);
 
-       return desc->its_inv_cmd.dev->collection;
+       return col;
 }
 
 static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
@@ -497,7 +529,7 @@ static void its_send_movi(struct its_device *dev,
 
        desc.its_movi_cmd.dev = dev;
        desc.its_movi_cmd.col = col;
-       desc.its_movi_cmd.id = id;
+       desc.its_movi_cmd.event_id = id;
 
        its_send_single_command(dev->its, its_build_movi_cmd, &desc);
 }
@@ -528,7 +560,7 @@ static void its_send_invall(struct its_node *its, struct its_collection *col)
 static inline u32 its_get_event_id(struct irq_data *d)
 {
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
-       return d->hwirq - its_dev->lpi_base;
+       return d->hwirq - its_dev->event_map.lpi_base;
 }
 
 static void lpi_set_config(struct irq_data *d, bool enable)
@@ -583,7 +615,7 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
 
        target_col = &its_dev->its->collections[cpu];
        its_send_movi(its_dev, target_col, id);
-       its_dev->collection = target_col;
+       its_dev->event_map.col_map[id] = cpu;
 
        return IRQ_SET_MASK_OK_DONE;
 }
@@ -713,8 +745,10 @@ out:
        return bitmap;
 }
 
-static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
+static void its_lpi_free(struct event_lpi_map *map)
 {
+       int base = map->lpi_base;
+       int nr_ids = map->nr_lpis;
        int lpi;
 
        spin_lock(&lpi_lock);
@@ -731,7 +765,8 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
 
        spin_unlock(&lpi_lock);
 
-       kfree(bitmap);
+       kfree(map->lpi_map);
+       kfree(map->col_map);
 }
 
 /*
@@ -1099,11 +1134,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        struct its_device *dev;
        unsigned long *lpi_map;
        unsigned long flags;
+       u16 *col_map = NULL;
        void *itt;
        int lpi_base;
        int nr_lpis;
        int nr_ites;
-       int cpu;
        int sz;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1117,20 +1152,24 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
        itt = kzalloc(sz, GFP_KERNEL);
        lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
+       if (lpi_map)
+               col_map = kzalloc(sizeof(*col_map) * nr_lpis, GFP_KERNEL);
 
-       if (!dev || !itt || !lpi_map) {
+       if (!dev || !itt || !lpi_map || !col_map) {
                kfree(dev);
                kfree(itt);
                kfree(lpi_map);
+               kfree(col_map);
                return NULL;
        }
 
        dev->its = its;
        dev->itt = itt;
        dev->nr_ites = nr_ites;
-       dev->lpi_map = lpi_map;
-       dev->lpi_base = lpi_base;
-       dev->nr_lpis = nr_lpis;
+       dev->event_map.lpi_map = lpi_map;
+       dev->event_map.col_map = col_map;
+       dev->event_map.lpi_base = lpi_base;
+       dev->event_map.nr_lpis = nr_lpis;
        dev->device_id = dev_id;
        INIT_LIST_HEAD(&dev->entry);
 
@@ -1138,10 +1177,6 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
        list_add(&dev->entry, &its->its_device_list);
        raw_spin_unlock_irqrestore(&its->lock, flags);
 
-       /* Bind the device to the first possible CPU */
-       cpu = cpumask_first(cpu_online_mask);
-       dev->collection = &its->collections[cpu];
-
        /* Map device to its ITT */
        its_send_mapd(dev, 1);
 
@@ -1163,12 +1198,13 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
 {
        int idx;
 
-       idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis);
-       if (idx == dev->nr_lpis)
+       idx = find_first_zero_bit(dev->event_map.lpi_map,
+                                 dev->event_map.nr_lpis);
+       if (idx == dev->event_map.nr_lpis)
                return -ENOSPC;
 
-       *hwirq = dev->lpi_base + idx;
-       set_bit(idx, dev->lpi_map);
+       *hwirq = dev->event_map.lpi_base + idx;
+       set_bit(idx, dev->event_map.lpi_map);
 
        return 0;
 }
@@ -1288,7 +1324,8 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
                irq_domain_set_hwirq_and_chip(domain, virq + i,
                                              hwirq, &its_irq_chip, its_dev);
                dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n",
-                       (int)(hwirq - its_dev->lpi_base), (int)hwirq, virq + i);
+                       (int)(hwirq - its_dev->event_map.lpi_base),
+                       (int)hwirq, virq + i);
        }
 
        return 0;
@@ -1300,6 +1337,9 @@ static void its_irq_domain_activate(struct irq_domain *domain,
        struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        u32 event = its_get_event_id(d);
 
+       /* Bind the LPI to the first possible CPU */
+       its_dev->event_map.col_map[event] = cpumask_first(cpu_online_mask);
+
        /* Map the GIC IRQ and event to the device */
        its_send_mapvi(its_dev, d->hwirq, event);
 }
@@ -1327,17 +1367,16 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
                u32 event = its_get_event_id(data);
 
                /* Mark interrupt index as unused */
-               clear_bit(event, its_dev->lpi_map);
+               clear_bit(event, its_dev->event_map.lpi_map);
 
                /* Nuke the entry in the domain */
                irq_domain_reset_irq_data(data);
        }
 
        /* If all interrupts have been freed, start mopping the floor */
-       if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
-               its_lpi_free(its_dev->lpi_map,
-                            its_dev->lpi_base,
-                            its_dev->nr_lpis);
+       if (bitmap_empty(its_dev->event_map.lpi_map,
+                        its_dev->event_map.nr_lpis)) {
+               its_lpi_free(&its_dev->event_map);
 
                /* Unmap device/itt */
                its_send_mapd(its_dev, 0);
index 8d7e1c8b6d566cb385c5cc92ff67c24f40692c9a..4dd88264dff55c0c95efd813c82fe762d7216263 100644 (file)
@@ -1055,7 +1055,7 @@ gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
 
        processor = (struct acpi_madt_generic_interrupt *)header;
 
-       if (BAD_MADT_ENTRY(processor, end))
+       if (BAD_MADT_GICC_ENTRY(processor, end))
                return -EINVAL;
 
        /*
index 4400edd1a6c729129357f5df0bdb37f7e8f018db..ff4be0515a0dc7dbb206ae0a84968f922817101e 100644 (file)
@@ -257,16 +257,6 @@ int gic_get_c0_fdc_int(void)
                return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
        }
 
-       /*
-        * Some cores claim the FDC is routable but it doesn't actually seem to
-        * be connected.
-        */
-       switch (current_cpu_type()) {
-       case CPU_INTERAPTIV:
-       case CPU_PROAPTIV:
-               return -1;
-       }
-
        return irq_create_mapping(gic_irq_domain,
                                  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
 }
@@ -548,7 +538,7 @@ static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 
 static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 {
-       smp_call_function_interrupt();
+       generic_smp_call_function_interrupt();
 
        return IRQ_HANDLED;
 }
index a45121546caff05acff16beb8d1dd2f4aa0d35c2..acb721b31bcfc4972921ff4c7f6afe1e1c8026cc 100644 (file)
@@ -2,7 +2,7 @@
  * SPEAr platform shared irq layer source file
  *
  * Copyright (C) 2009-2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * Copyright (C) 2012 ST Microelectronics
  * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
index 8c91fd5eb6fdd4696f8b6d298eef8684525fc94e..375be509e95f5bd302da79446cb8867f8ecb8ec7 100644 (file)
@@ -524,9 +524,18 @@ gigaset_tty_open(struct tty_struct *tty)
        cs->hw.ser->tty = tty;
        atomic_set(&cs->hw.ser->refcnt, 1);
        init_completion(&cs->hw.ser->dead_cmp);
-
        tty->disc_data = cs;
 
+       /* Set the amount of data we're willing to receive per call
+        * from the hardware driver to half of the input buffer size
+        * to leave some reserve.
+        * Note: We don't do flow control towards the hardware driver.
+        * If more data is received than will fit into the input buffer,
+        * it will be dropped and an error will be logged. This should
+        * never happen as the device is slow and the buffer size ample.
+        */
+       tty->receive_room = RBUFSIZE/2;
+
        /* OK.. Initialization of the datastructures and the HW is done.. Now
         * startup system and notify the LL that we are ready to run
         */
@@ -597,28 +606,6 @@ static int gigaset_tty_hangup(struct tty_struct *tty)
        return 0;
 }
 
-/*
- * Read on the tty.
- * Unused, received data goes only to the Gigaset driver.
- */
-static ssize_t
-gigaset_tty_read(struct tty_struct *tty, struct file *file,
-                unsigned char __user *buf, size_t count)
-{
-       return -EAGAIN;
-}
-
-/*
- * Write on the tty.
- * Unused, transmit data comes only from the Gigaset driver.
- */
-static ssize_t
-gigaset_tty_write(struct tty_struct *tty, struct file *file,
-                 const unsigned char *buf, size_t count)
-{
-       return -EAGAIN;
-}
-
 /*
  * Ioctl on the tty.
  * Called in process context only.
@@ -752,8 +739,6 @@ static struct tty_ldisc_ops gigaset_ldisc = {
        .open           = gigaset_tty_open,
        .close          = gigaset_tty_close,
        .hangup         = gigaset_tty_hangup,
-       .read           = gigaset_tty_read,
-       .write          = gigaset_tty_write,
        .ioctl          = gigaset_tty_ioctl,
        .receive_buf    = gigaset_tty_receive,
        .write_wakeup   = gigaset_tty_wakeup,
index 1a57e88a38f7554ef3c09199090ce52575d041ef..cd35079c8c98b69469e1e64794b6a7345c382f3b 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/fcntl.h>
-#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 
index b59727309072462fb3d0dc42935000d9570a7589..bfec3bdfe59847c8f3553e178a8b33a1c5a708fd 100644 (file)
@@ -259,7 +259,7 @@ config DM_CRYPT
          the ciphers you're going to use in the cryptoapi configuration.
 
          For further information on dm-crypt and userspace tools see:
-         <http://code.google.com/p/cryptsetup/wiki/DMCrypt>
+         <https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt>
 
          To compile this code as a module, choose M here: the module will
          be called dm-crypt.
index a08e3eeac3c5fbf389ede37b839f40f705cd4d47..79a6d63e8ed3dce7b5bf936face73542af0a77d8 100644 (file)
@@ -320,7 +320,6 @@ static inline void closure_wake_up(struct closure_waitlist *list)
 do {                                                                   \
        set_closure_fn(_cl, _fn, _wq);                                  \
        closure_sub(_cl, CLOSURE_RUNNING + 1);                          \
-       return;                                                         \
 } while (0)
 
 /**
@@ -349,7 +348,6 @@ do {                                                                        \
 do {                                                                   \
        set_closure_fn(_cl, _fn, _wq);                                  \
        closure_queue(_cl);                                             \
-       return;                                                         \
 } while (0)
 
 /**
@@ -365,7 +363,6 @@ do {                                                                        \
 do {                                                                   \
        set_closure_fn(_cl, _destructor, NULL);                         \
        closure_sub(_cl, CLOSURE_RUNNING - CLOSURE_DESTRUCTOR + 1);     \
-       return;                                                         \
 } while (0)
 
 /**
index cb64e64a478954e5c7dec8f774df29852fad0e01..bf6a9ca18403f3a8bb0d289f43235eb59d79c786 100644 (file)
@@ -105,6 +105,7 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
        } while (n != bio);
 
        continue_at(&s->cl, bch_bio_submit_split_done, NULL);
+       return;
 submit:
        generic_make_request(bio);
 }
index ce64fc8512518c6bff63b9a551d931341aaf6f84..418607a6ba33442c09b85dc9ea2070fee88de0ca 100644 (file)
@@ -592,12 +592,14 @@ static void journal_write_unlocked(struct closure *cl)
 
        if (!w->need_write) {
                closure_return_with_destructor(cl, journal_write_unlock);
+               return;
        } else if (journal_full(&c->journal)) {
                journal_reclaim(c);
                spin_unlock(&c->journal.lock);
 
                btree_flush_write(c);
                continue_at(cl, journal_write, system_wq);
+               return;
        }
 
        c->journal.blocks_free -= set_blocks(w->data, block_bytes(c));
index 4afb2d26b148a3a41ca55171dee89d75da64e4f4..f292790997d72b98fc633dd3da089d93443fbdfa 100644 (file)
@@ -88,8 +88,10 @@ static void bch_data_insert_keys(struct closure *cl)
        if (journal_ref)
                atomic_dec_bug(journal_ref);
 
-       if (!op->insert_data_done)
+       if (!op->insert_data_done) {
                continue_at(cl, bch_data_insert_start, op->wq);
+               return;
+       }
 
        bch_keylist_free(&op->insert_keys);
        closure_return(cl);
@@ -216,8 +218,10 @@ static void bch_data_insert_start(struct closure *cl)
                /* 1 for the device pointer and 1 for the chksum */
                if (bch_keylist_realloc(&op->insert_keys,
                                        3 + (op->csum ? 1 : 0),
-                                       op->c))
+                                       op->c)) {
                        continue_at(cl, bch_data_insert_keys, op->wq);
+                       return;
+               }
 
                k = op->insert_keys.top;
                bkey_init(k);
@@ -255,6 +259,7 @@ static void bch_data_insert_start(struct closure *cl)
 
        op->insert_data_done = true;
        continue_at(cl, bch_data_insert_keys, op->wq);
+       return;
 err:
        /* bch_alloc_sectors() blocks if s->writeback = true */
        BUG_ON(op->writeback);
@@ -576,8 +581,10 @@ static void cache_lookup(struct closure *cl)
        ret = bch_btree_map_keys(&s->op, s->iop.c,
                                 &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0),
                                 cache_lookup_fn, MAP_END_KEY);
-       if (ret == -EAGAIN)
+       if (ret == -EAGAIN) {
                continue_at(cl, cache_lookup, bcache_wq);
+               return;
+       }
 
        closure_return(cl);
 }
@@ -1085,6 +1092,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
                continue_at_nobarrier(&s->cl,
                                      flash_dev_nodata,
                                      bcache_wq);
+               return;
        } else if (rw) {
                bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys,
                                        &KEY(d->id, bio->bi_iter.bi_sector, 0),
index ed2346ddf4c9fb54dafeb92ae9c795a0584444e8..e51de52eeb94f71c9d6712a61d31e49f8e6f2f60 100644 (file)
@@ -494,7 +494,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
        bitmap_super_t *sb;
        unsigned long chunksize, daemon_sleep, write_behind;
 
-       bitmap->storage.sb_page = alloc_page(GFP_KERNEL);
+       bitmap->storage.sb_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (bitmap->storage.sb_page == NULL)
                return -ENOMEM;
        bitmap->storage.sb_page->index = 0;
@@ -541,6 +541,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
        sb->state = cpu_to_le32(bitmap->flags);
        bitmap->events_cleared = bitmap->mddev->events;
        sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
+       bitmap->mddev->bitmap_info.nodes = 0;
 
        kunmap_atomic(sb);
 
@@ -558,6 +559,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
        unsigned long sectors_reserved = 0;
        int err = -EINVAL;
        struct page *sb_page;
+       loff_t offset = bitmap->mddev->bitmap_info.offset;
 
        if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) {
                chunksize = 128 * 1024 * 1024;
@@ -584,9 +586,9 @@ re_read:
                bm_blocks = ((bm_blocks+7) >> 3) + sizeof(bitmap_super_t);
                /* to 4k blocks */
                bm_blocks = DIV_ROUND_UP_SECTOR_T(bm_blocks, 4096);
-               bitmap->mddev->bitmap_info.offset += bitmap->cluster_slot * (bm_blocks << 3);
+               offset = bitmap->mddev->bitmap_info.offset + (bitmap->cluster_slot * (bm_blocks << 3));
                pr_info("%s:%d bm slot: %d offset: %llu\n", __func__, __LINE__,
-                       bitmap->cluster_slot, (unsigned long long)bitmap->mddev->bitmap_info.offset);
+                       bitmap->cluster_slot, offset);
        }
 
        if (bitmap->storage.file) {
@@ -597,7 +599,7 @@ re_read:
                                bitmap, bytes, sb_page);
        } else {
                err = read_sb_page(bitmap->mddev,
-                                  bitmap->mddev->bitmap_info.offset,
+                                  offset,
                                   sb_page,
                                   0, sizeof(bitmap_super_t));
        }
@@ -611,8 +613,16 @@ re_read:
        daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
        write_behind = le32_to_cpu(sb->write_behind);
        sectors_reserved = le32_to_cpu(sb->sectors_reserved);
-       nodes = le32_to_cpu(sb->nodes);
-       strlcpy(bitmap->mddev->bitmap_info.cluster_name, sb->cluster_name, 64);
+       /* XXX: This is a hack to ensure that we don't use clustering
+        *  in case:
+        *      - dm-raid is in use and
+        *      - the nodes written in bitmap_sb is erroneous.
+        */
+       if (!bitmap->mddev->sync_super) {
+               nodes = le32_to_cpu(sb->nodes);
+               strlcpy(bitmap->mddev->bitmap_info.cluster_name,
+                               sb->cluster_name, 64);
+       }
 
        /* verify that the bitmap-specific fields are valid */
        if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
@@ -671,7 +681,7 @@ out:
        kunmap_atomic(sb);
        /* Assiging chunksize is required for "re_read" */
        bitmap->mddev->bitmap_info.chunksize = chunksize;
-       if (nodes && (bitmap->cluster_slot < 0)) {
+       if (err == 0 && nodes && (bitmap->cluster_slot < 0)) {
                err = md_setup_cluster(bitmap->mddev, nodes);
                if (err) {
                        pr_err("%s: Could not setup cluster service (%d)\n",
@@ -1866,10 +1876,6 @@ int bitmap_copy_from_slot(struct mddev *mddev, int slot,
        if (IS_ERR(bitmap))
                return PTR_ERR(bitmap);
 
-       rv = bitmap_read_sb(bitmap);
-       if (rv)
-               goto err;
-
        rv = bitmap_init_from_disk(bitmap, 0);
        if (rv)
                goto err;
index 32814371b8d304539a2eb1cfece077510b4ca394..aa1b41ca40f778dcb4e6c0e393ab4ee33d25d388 100644 (file)
@@ -1471,5 +1471,3 @@ module_exit(mq_exit);
 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("mq cache policy");
-
-MODULE_ALIAS("dm-cache-default");
index b6f22651dd356e7e5b4d0bed4268f4ac9dd62772..200366c62231dd5f8f38f74284a42810c8603d19 100644 (file)
@@ -1686,7 +1686,7 @@ static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
 
        if (from_cblock(cache_size)) {
                mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size));
-               if (!mq->cache_hit_bits && mq->cache_hit_bits) {
+               if (!mq->cache_hit_bits) {
                        DMERR("couldn't allocate cache hit bitset");
                        goto bad_cache_hit_bits;
                }
@@ -1789,3 +1789,5 @@ module_exit(smq_exit);
 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("smq cache policy");
+
+MODULE_ALIAS("dm-cache-default");
index 1b4e1756b169dab9d7377dcea444087176830652..1fe93cfea7d309a659d79fe2b953b5f2dbe7b466 100644 (file)
@@ -1947,6 +1947,7 @@ static int commit_if_needed(struct cache *cache)
 
 static void process_deferred_bios(struct cache *cache)
 {
+       bool prealloc_used = false;
        unsigned long flags;
        struct bio_list bios;
        struct bio *bio;
@@ -1966,6 +1967,7 @@ static void process_deferred_bios(struct cache *cache)
                 * this bio might require one, we pause until there are some
                 * prepared mappings to process.
                 */
+               prealloc_used = true;
                if (prealloc_data_structs(cache, &structs)) {
                        spin_lock_irqsave(&cache->lock, flags);
                        bio_list_merge(&cache->deferred_bios, &bios);
@@ -1983,11 +1985,13 @@ static void process_deferred_bios(struct cache *cache)
                        process_bio(cache, &structs, bio);
        }
 
-       prealloc_free_structs(cache, &structs);
+       if (prealloc_used)
+               prealloc_free_structs(cache, &structs);
 }
 
 static void process_deferred_cells(struct cache *cache)
 {
+       bool prealloc_used = false;
        unsigned long flags;
        struct dm_bio_prison_cell *cell, *tmp;
        struct list_head cells;
@@ -2007,6 +2011,7 @@ static void process_deferred_cells(struct cache *cache)
                 * this bio might require one, we pause until there are some
                 * prepared mappings to process.
                 */
+               prealloc_used = true;
                if (prealloc_data_structs(cache, &structs)) {
                        spin_lock_irqsave(&cache->lock, flags);
                        list_splice(&cells, &cache->deferred_cells);
@@ -2017,7 +2022,8 @@ static void process_deferred_cells(struct cache *cache)
                process_cell(cache, &structs, cell);
        }
 
-       prealloc_free_structs(cache, &structs);
+       if (prealloc_used)
+               prealloc_free_structs(cache, &structs);
 }
 
 static void process_deferred_flush_bios(struct cache *cache, bool submit_bios)
@@ -2062,7 +2068,7 @@ static void process_deferred_writethrough_bios(struct cache *cache)
 
 static void writeback_some_dirty_blocks(struct cache *cache)
 {
-       int r = 0;
+       bool prealloc_used = false;
        dm_oblock_t oblock;
        dm_cblock_t cblock;
        struct prealloc structs;
@@ -2072,15 +2078,12 @@ static void writeback_some_dirty_blocks(struct cache *cache)
        memset(&structs, 0, sizeof(structs));
 
        while (spare_migration_bandwidth(cache)) {
-               if (prealloc_data_structs(cache, &structs))
-                       break;
-
-               r = policy_writeback_work(cache->policy, &oblock, &cblock, busy);
-               if (r)
-                       break;
+               if (policy_writeback_work(cache->policy, &oblock, &cblock, busy))
+                       break; /* no work to do */
 
-               r = get_cell(cache, oblock, &structs, &old_ocell);
-               if (r) {
+               prealloc_used = true;
+               if (prealloc_data_structs(cache, &structs) ||
+                   get_cell(cache, oblock, &structs, &old_ocell)) {
                        policy_set_dirty(cache->policy, oblock);
                        break;
                }
@@ -2088,7 +2091,8 @@ static void writeback_some_dirty_blocks(struct cache *cache)
                writeback(cache, &structs, oblock, cblock, old_ocell);
        }
 
-       prealloc_free_structs(cache, &structs);
+       if (prealloc_used)
+               prealloc_free_structs(cache, &structs);
 }
 
 /*----------------------------------------------------------------
@@ -3496,7 +3500,7 @@ static void cache_resume(struct dm_target *ti)
  * <#demotions> <#promotions> <#dirty>
  * <#features> <features>*
  * <#core args> <core args>
- * <policy name> <#policy args> <policy args>* <cache metadata mode>
+ * <policy name> <#policy args> <policy args>* <cache metadata mode> <needs_check>
  */
 static void cache_status(struct dm_target *ti, status_type_t type,
                         unsigned status_flags, char *result, unsigned maxlen)
@@ -3582,6 +3586,11 @@ static void cache_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("rw ");
 
+               if (dm_cache_metadata_needs_check(cache->cmd))
+                       DMEMIT("needs_check ");
+               else
+                       DMEMIT("- ");
+
                break;
 
        case STATUSTYPE_TABLE:
@@ -3820,7 +3829,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type cache_target = {
        .name = "cache",
-       .version = {1, 7, 0},
+       .version = {1, 8, 0},
        .module = THIS_MODULE,
        .ctr = cache_ctr,
        .dtr = cache_dtr,
index 48dfe3c4d6aa7968bbc1986eafcb9e965fe55950..6ba47cfb1443748ccf092819a6a5ef160bb856fd 100644 (file)
@@ -1293,8 +1293,8 @@ static int __release_metadata_snap(struct dm_pool_metadata *pmd)
                return r;
 
        disk_super = dm_block_data(copy);
-       dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->data_mapping_root));
-       dm_sm_dec_block(pmd->metadata_sm, le64_to_cpu(disk_super->device_details_root));
+       dm_btree_del(&pmd->info, le64_to_cpu(disk_super->data_mapping_root));
+       dm_btree_del(&pmd->details_info, le64_to_cpu(disk_super->device_details_root));
        dm_sm_dec_block(pmd->metadata_sm, held_root);
 
        return dm_tm_unlock(pmd->tm, copy);
index c33f61a4cc28d8b772b9444b710e7f55fa6df2fb..d2bbe8cc1e9786b66af798df9d8666d3fb96223c 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/sort.h>
 #include <linux/rbtree.h>
 
@@ -268,7 +269,7 @@ struct pool {
        process_mapping_fn process_prepared_mapping;
        process_mapping_fn process_prepared_discard;
 
-       struct dm_bio_prison_cell *cell_sort_array[CELL_SORT_ARRAY_SIZE];
+       struct dm_bio_prison_cell **cell_sort_array;
 };
 
 static enum pool_mode get_pool_mode(struct pool *pool);
@@ -665,16 +666,21 @@ static void requeue_io(struct thin_c *tc)
        requeue_deferred_cells(tc);
 }
 
-static void error_retry_list(struct pool *pool)
+static void error_retry_list_with_code(struct pool *pool, int error)
 {
        struct thin_c *tc;
 
        rcu_read_lock();
        list_for_each_entry_rcu(tc, &pool->active_thins, list)
-               error_thin_bio_list(tc, &tc->retry_on_resume_list, -EIO);
+               error_thin_bio_list(tc, &tc->retry_on_resume_list, error);
        rcu_read_unlock();
 }
 
+static void error_retry_list(struct pool *pool)
+{
+       return error_retry_list_with_code(pool, -EIO);
+}
+
 /*
  * This section of code contains the logic for processing a thin device's IO.
  * Much of the code depends on pool object resources (lists, workqueues, etc)
@@ -2281,18 +2287,23 @@ static void do_waker(struct work_struct *ws)
        queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD);
 }
 
+static void notify_of_pool_mode_change_to_oods(struct pool *pool);
+
 /*
  * We're holding onto IO to allow userland time to react.  After the
  * timeout either the pool will have been resized (and thus back in
- * PM_WRITE mode), or we degrade to PM_READ_ONLY and start erroring IO.
+ * PM_WRITE mode), or we degrade to PM_OUT_OF_DATA_SPACE w/ error_if_no_space.
  */
 static void do_no_space_timeout(struct work_struct *ws)
 {
        struct pool *pool = container_of(to_delayed_work(ws), struct pool,
                                         no_space_timeout);
 
-       if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space)
-               set_pool_mode(pool, PM_READ_ONLY);
+       if (get_pool_mode(pool) == PM_OUT_OF_DATA_SPACE && !pool->pf.error_if_no_space) {
+               pool->pf.error_if_no_space = true;
+               notify_of_pool_mode_change_to_oods(pool);
+               error_retry_list_with_code(pool, -ENOSPC);
+       }
 }
 
 /*----------------------------------------------------------------*/
@@ -2370,6 +2381,14 @@ static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode)
               dm_device_name(pool->pool_md), new_mode);
 }
 
+static void notify_of_pool_mode_change_to_oods(struct pool *pool)
+{
+       if (!pool->pf.error_if_no_space)
+               notify_of_pool_mode_change(pool, "out-of-data-space (queue IO)");
+       else
+               notify_of_pool_mode_change(pool, "out-of-data-space (error IO)");
+}
+
 static bool passdown_enabled(struct pool_c *pt)
 {
        return pt->adjusted_pf.discard_passdown;
@@ -2454,7 +2473,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
                 * frequently seeing this mode.
                 */
                if (old_mode != new_mode)
-                       notify_of_pool_mode_change(pool, "out-of-data-space");
+                       notify_of_pool_mode_change_to_oods(pool);
                pool->process_bio = process_bio_read_only;
                pool->process_discard = process_discard_bio;
                pool->process_cell = process_cell_read_only;
@@ -2777,6 +2796,7 @@ static void __pool_destroy(struct pool *pool)
 {
        __pool_table_remove(pool);
 
+       vfree(pool->cell_sort_array);
        if (dm_pool_metadata_close(pool->pmd) < 0)
                DMWARN("%s: dm_pool_metadata_close() failed.", __func__);
 
@@ -2889,6 +2909,13 @@ static struct pool *pool_create(struct mapped_device *pool_md,
                goto bad_mapping_pool;
        }
 
+       pool->cell_sort_array = vmalloc(sizeof(*pool->cell_sort_array) * CELL_SORT_ARRAY_SIZE);
+       if (!pool->cell_sort_array) {
+               *error = "Error allocating cell sort array";
+               err_p = ERR_PTR(-ENOMEM);
+               goto bad_sort_array;
+       }
+
        pool->ref_count = 1;
        pool->last_commit_jiffies = jiffies;
        pool->pool_md = pool_md;
@@ -2897,6 +2924,8 @@ static struct pool *pool_create(struct mapped_device *pool_md,
 
        return pool;
 
+bad_sort_array:
+       mempool_destroy(pool->mapping_pool);
 bad_mapping_pool:
        dm_deferred_set_destroy(pool->all_io_ds);
 bad_all_io_ds:
@@ -3714,6 +3743,7 @@ static void emit_flags(struct pool_features *pf, char *result,
  * Status line is:
  *    <transaction id> <used metadata sectors>/<total metadata sectors>
  *    <used data sectors>/<total data sectors> <held metadata root>
+ *    <pool mode> <discard config> <no space config> <needs_check>
  */
 static void pool_status(struct dm_target *ti, status_type_t type,
                        unsigned status_flags, char *result, unsigned maxlen)
@@ -3815,6 +3845,11 @@ static void pool_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("queue_if_no_space ");
 
+               if (dm_pool_metadata_needs_check(pool->pmd))
+                       DMEMIT("needs_check ");
+               else
+                       DMEMIT("- ");
+
                break;
 
        case STATUSTYPE_TABLE:
@@ -3918,7 +3953,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 15, 0},
+       .version = {1, 16, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -4305,7 +4340,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 15, 0},
+       .version = {1, 16, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
index f331d888e7f5a52cd5a2ada7498a5051bd8e38ca..0d7ab20c58dffc40d5c56c9427b7dd7f090c8bd3 100644 (file)
@@ -1067,13 +1067,10 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig)
  */
 static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
 {
-       int nr_requests_pending;
-
        atomic_dec(&md->pending[rw]);
 
        /* nudge anyone waiting on suspend queue */
-       nr_requests_pending = md_in_flight(md);
-       if (!nr_requests_pending)
+       if (!md_in_flight(md))
                wake_up(&md->wait);
 
        /*
@@ -1085,8 +1082,7 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
        if (run_queue) {
                if (md->queue->mq_ops)
                        blk_mq_run_hw_queues(md->queue, true);
-               else if (!nr_requests_pending ||
-                        (nr_requests_pending >= md->queue->nr_congestion_on))
+               else
                        blk_run_queue_async(md->queue);
        }
 
@@ -1733,7 +1729,8 @@ static int dm_merge_bvec(struct request_queue *q,
        struct mapped_device *md = q->queuedata;
        struct dm_table *map = dm_get_live_table_fast(md);
        struct dm_target *ti;
-       sector_t max_sectors, max_size = 0;
+       sector_t max_sectors;
+       int max_size = 0;
 
        if (unlikely(!map))
                goto out;
@@ -1746,18 +1743,10 @@ static int dm_merge_bvec(struct request_queue *q,
         * Find maximum amount of I/O that won't need splitting
         */
        max_sectors = min(max_io_len(bvm->bi_sector, ti),
-                         (sector_t) queue_max_sectors(q));
+                         (sector_t) BIO_MAX_SECTORS);
        max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
-
-       /*
-        * FIXME: this stop-gap fix _must_ be cleaned up (by passing a sector_t
-        * to the targets' merge function since it holds sectors not bytes).
-        * Just doing this as an interim fix for stable@ because the more
-        * comprehensive cleanup of switching to sector_t will impact every
-        * DM target that implements a ->merge hook.
-        */
-       if (max_size > INT_MAX)
-               max_size = INT_MAX;
+       if (max_size < 0)
+               max_size = 0;
 
        /*
         * merge_bvec_fn() returns number of bytes
@@ -1765,13 +1754,13 @@ static int dm_merge_bvec(struct request_queue *q,
         * max is precomputed maximal io size
         */
        if (max_size && ti->type->merge)
-               max_size = ti->type->merge(ti, bvm, biovec, (int) max_size);
+               max_size = ti->type->merge(ti, bvm, biovec, max_size);
        /*
         * If the target doesn't support merge method and some of the devices
-        * provided their merge_bvec method (we know this by looking for the
-        * max_hw_sectors that dm_set_device_limits may set), then we can't
-        * allow bios with multiple vector entries.  So always set max_size
-        * to 0, and the code below allows just one page.
+        * provided their merge_bvec method (we know this by looking at
+        * queue_max_hw_sectors), then we can't allow bios with multiple vector
+        * entries.  So always set max_size to 0, and the code below allows
+        * just one page.
         */
        else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
                max_size = 0;
@@ -2281,8 +2270,6 @@ static void dm_init_old_md_queue(struct mapped_device *md)
 
 static void cleanup_mapped_device(struct mapped_device *md)
 {
-       cleanup_srcu_struct(&md->io_barrier);
-
        if (md->wq)
                destroy_workqueue(md->wq);
        if (md->kworker_task)
@@ -2294,6 +2281,8 @@ static void cleanup_mapped_device(struct mapped_device *md)
        if (md->bs)
                bioset_free(md->bs);
 
+       cleanup_srcu_struct(&md->io_barrier);
+
        if (md->disk) {
                spin_lock(&_minor_lock);
                md->disk->private_data = NULL;
index fcfc4b9b26728029e59023ae3762d271b8f7a676..0072190515e0f6edca1e09718dae5102b3e7d274 100644 (file)
@@ -44,6 +44,7 @@ struct resync_info {
 
 /* md_cluster_info flags */
 #define                MD_CLUSTER_WAITING_FOR_NEWDISK          1
+#define                MD_CLUSTER_SUSPEND_READ_BALANCING       2
 
 
 struct md_cluster_info {
@@ -275,6 +276,9 @@ clear_bit:
 
 static void recover_prep(void *arg)
 {
+       struct mddev *mddev = arg;
+       struct md_cluster_info *cinfo = mddev->cluster_info;
+       set_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state);
 }
 
 static void recover_slot(void *arg, struct dlm_slot *slot)
@@ -307,6 +311,7 @@ static void recover_done(void *arg, struct dlm_slot *slots,
 
        cinfo->slot_number = our_slot;
        complete(&cinfo->completion);
+       clear_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state);
 }
 
 static const struct dlm_lockspace_ops md_ls_ops = {
@@ -816,12 +821,17 @@ static void resync_finish(struct mddev *mddev)
        resync_send(mddev, RESYNCING, 0, 0);
 }
 
-static int area_resyncing(struct mddev *mddev, sector_t lo, sector_t hi)
+static int area_resyncing(struct mddev *mddev, int direction,
+               sector_t lo, sector_t hi)
 {
        struct md_cluster_info *cinfo = mddev->cluster_info;
        int ret = 0;
        struct suspend_info *s;
 
+       if ((direction == READ) &&
+               test_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state))
+               return 1;
+
        spin_lock_irq(&cinfo->suspend_lock);
        if (list_empty(&cinfo->suspend_list))
                goto out;
index 6817ee00e053d7d7e74b734185414c0cb3b18a38..00defe2badbc7952ec7d4cf358ad0408a2460b7f 100644 (file)
@@ -18,7 +18,7 @@ struct md_cluster_operations {
        int (*metadata_update_start)(struct mddev *mddev);
        int (*metadata_update_finish)(struct mddev *mddev);
        int (*metadata_update_cancel)(struct mddev *mddev);
-       int (*area_resyncing)(struct mddev *mddev, sector_t lo, sector_t hi);
+       int (*area_resyncing)(struct mddev *mddev, int direction, sector_t lo, sector_t hi);
        int (*add_new_disk_start)(struct mddev *mddev, struct md_rdev *rdev);
        int (*add_new_disk_finish)(struct mddev *mddev);
        int (*new_disk_ack)(struct mddev *mddev, bool ack);
index d429c30cd51471c26cb1c07cb3e6a413106133d4..e25f00f0138a7b4d82a5ae4f6fc7e1b6f0bb1b30 100644 (file)
@@ -5382,6 +5382,8 @@ static void __md_stop(struct mddev *mddev)
 {
        struct md_personality *pers = mddev->pers;
        mddev_detach(mddev);
+       /* Ensure ->event_work is done */
+       flush_workqueue(md_misc_wq);
        spin_lock(&mddev->lock);
        mddev->ready = 0;
        mddev->pers = NULL;
@@ -5757,7 +5759,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg)
        char *ptr;
        int err;
 
-       file = kmalloc(sizeof(*file), GFP_NOIO);
+       file = kzalloc(sizeof(*file), GFP_NOIO);
        if (!file)
                return -ENOMEM;
 
@@ -7437,7 +7439,7 @@ int md_setup_cluster(struct mddev *mddev, int nodes)
        err = request_module("md-cluster");
        if (err) {
                pr_err("md-cluster module not found.\n");
-               return err;
+               return -ENOENT;
        }
 
        spin_lock(&pers_lock);
index bf2b80d5c4707a64210b5e57deb785069dc7d921..8731b6ea026bd9b8cfbe2a21bbc06366e509181c 100644 (file)
@@ -138,4 +138,10 @@ int lower_bound(struct btree_node *n, uint64_t key);
 
 extern struct dm_block_validator btree_node_validator;
 
+/*
+ * Value type for upper levels of multi-level btrees.
+ */
+extern void init_le64_type(struct dm_transaction_manager *tm,
+                          struct dm_btree_value_type *vt);
+
 #endif /* DM_BTREE_INTERNAL_H */
index e04cfd2d60ef9b2d80ee89baa0fb2136bf3cd2ab..4222f774cf369b1eb1b031bd652854c573b224af 100644 (file)
@@ -309,8 +309,8 @@ static void redistribute3(struct dm_btree_info *info, struct btree_node *parent,
 
                if (s < 0 && nr_center < -s) {
                        /* not enough in central node */
-                       shift(left, center, nr_center);
-                       s = nr_center - target;
+                       shift(left, center, -nr_center);
+                       s += nr_center;
                        shift(left, right, s);
                        nr_right += s;
                } else
@@ -323,7 +323,7 @@ static void redistribute3(struct dm_btree_info *info, struct btree_node *parent,
                if (s > 0 && nr_center < s) {
                        /* not enough in central node */
                        shift(center, right, nr_center);
-                       s = target - nr_center;
+                       s -= nr_center;
                        shift(left, right, s);
                        nr_left -= s;
                } else
@@ -544,14 +544,6 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
        return r;
 }
 
-static struct dm_btree_value_type le64_type = {
-       .context = NULL,
-       .size = sizeof(__le64),
-       .inc = NULL,
-       .dec = NULL,
-       .equal = NULL
-};
-
 int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
                    uint64_t *keys, dm_block_t *new_root)
 {
@@ -559,12 +551,14 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
        int index = 0, r = 0;
        struct shadow_spine spine;
        struct btree_node *n;
+       struct dm_btree_value_type le64_vt;
 
+       init_le64_type(info->tm, &le64_vt);
        init_shadow_spine(&spine, info);
        for (level = 0; level < info->levels; level++) {
                r = remove_raw(&spine, info,
                               (level == last_level ?
-                               &info->value_type : &le64_type),
+                               &info->value_type : &le64_vt),
                               root, keys[level], (unsigned *)&index);
                if (r < 0)
                        break;
@@ -654,11 +648,13 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
        int index = 0, r = 0;
        struct shadow_spine spine;
        struct btree_node *n;
+       struct dm_btree_value_type le64_vt;
        uint64_t k;
 
+       init_le64_type(info->tm, &le64_vt);
        init_shadow_spine(&spine, info);
        for (level = 0; level < last_level; level++) {
-               r = remove_raw(&spine, info, &le64_type,
+               r = remove_raw(&spine, info, &le64_vt,
                               root, keys[level], (unsigned *) &index);
                if (r < 0)
                        goto out;
@@ -689,6 +685,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
                                             value_ptr(n, index));
 
                delete_at(n, index);
+               keys[last_level] = k + 1ull;
 
        } else
                r = -ENODATA;
index 1b5e13ec7f96a670ed7a9b5b472a5d2ee95a7dff..0dee514ba4c5f9e8d34d16e9d239ef333395c7d4 100644 (file)
@@ -249,3 +249,40 @@ int shadow_root(struct shadow_spine *s)
 {
        return s->root;
 }
+
+static void le64_inc(void *context, const void *value_le)
+{
+       struct dm_transaction_manager *tm = context;
+       __le64 v_le;
+
+       memcpy(&v_le, value_le, sizeof(v_le));
+       dm_tm_inc(tm, le64_to_cpu(v_le));
+}
+
+static void le64_dec(void *context, const void *value_le)
+{
+       struct dm_transaction_manager *tm = context;
+       __le64 v_le;
+
+       memcpy(&v_le, value_le, sizeof(v_le));
+       dm_tm_dec(tm, le64_to_cpu(v_le));
+}
+
+static int le64_equal(void *context, const void *value1_le, const void *value2_le)
+{
+       __le64 v1_le, v2_le;
+
+       memcpy(&v1_le, value1_le, sizeof(v1_le));
+       memcpy(&v2_le, value2_le, sizeof(v2_le));
+       return v1_le == v2_le;
+}
+
+void init_le64_type(struct dm_transaction_manager *tm,
+                   struct dm_btree_value_type *vt)
+{
+       vt->context = tm;
+       vt->size = sizeof(__le64);
+       vt->inc = le64_inc;
+       vt->dec = le64_dec;
+       vt->equal = le64_equal;
+}
index 200ac12a1d407b5c648c7271a995a022ac8e7efc..c7726cebc4950c24cb6f6f2b7cacfa6465bddeb6 100644 (file)
@@ -255,7 +255,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
        int r;
        struct del_stack *s;
 
-       s = kmalloc(sizeof(*s), GFP_KERNEL);
+       s = kmalloc(sizeof(*s), GFP_NOIO);
        if (!s)
                return -ENOMEM;
        s->info = info;
@@ -667,12 +667,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
        struct btree_node *n;
        struct dm_btree_value_type le64_type;
 
-       le64_type.context = NULL;
-       le64_type.size = sizeof(__le64);
-       le64_type.inc = NULL;
-       le64_type.dec = NULL;
-       le64_type.equal = NULL;
-
+       init_le64_type(info->tm, &le64_type);
        init_shadow_spine(&spine, info);
 
        for (level = 0; level < (info->levels - 1); level++) {
index f80f1af61ce70bce15a72d242d87c1c34da49a79..967a4ed73929ff44a38d9475c5e362fc2914c758 100644 (file)
@@ -336,7 +336,7 @@ static void raid1_end_read_request(struct bio *bio, int error)
                spin_lock_irqsave(&conf->device_lock, flags);
                if (r1_bio->mddev->degraded == conf->raid_disks ||
                    (r1_bio->mddev->degraded == conf->raid_disks-1 &&
-                    !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags)))
+                    test_bit(In_sync, &conf->mirrors[mirror].rdev->flags)))
                        uptodate = 1;
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
@@ -541,7 +541,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
 
        if ((conf->mddev->recovery_cp < this_sector + sectors) ||
            (mddev_is_clustered(conf->mddev) &&
-           md_cluster_ops->area_resyncing(conf->mddev, this_sector,
+           md_cluster_ops->area_resyncing(conf->mddev, READ, this_sector,
                    this_sector + sectors)))
                choose_first = 1;
        else
@@ -1111,7 +1111,8 @@ static void make_request(struct mddev *mddev, struct bio * bio)
            ((bio_end_sector(bio) > mddev->suspend_lo &&
            bio->bi_iter.bi_sector < mddev->suspend_hi) ||
            (mddev_is_clustered(mddev) &&
-            md_cluster_ops->area_resyncing(mddev, bio->bi_iter.bi_sector, bio_end_sector(bio))))) {
+            md_cluster_ops->area_resyncing(mddev, WRITE,
+                    bio->bi_iter.bi_sector, bio_end_sector(bio))))) {
                /* As the suspend_* range is controlled by
                 * userspace, we want an interruptible
                 * wait.
@@ -1124,7 +1125,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
                        if (bio_end_sector(bio) <= mddev->suspend_lo ||
                            bio->bi_iter.bi_sector >= mddev->suspend_hi ||
                            (mddev_is_clustered(mddev) &&
-                            !md_cluster_ops->area_resyncing(mddev,
+                            !md_cluster_ops->area_resyncing(mddev, WRITE,
                                     bio->bi_iter.bi_sector, bio_end_sector(bio))))
                                break;
                        schedule();
@@ -1475,6 +1476,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
 {
        char b[BDEVNAME_SIZE];
        struct r1conf *conf = mddev->private;
+       unsigned long flags;
 
        /*
         * If it is not operational, then we have already marked it as dead
@@ -1494,14 +1496,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
                return;
        }
        set_bit(Blocked, &rdev->flags);
+       spin_lock_irqsave(&conf->device_lock, flags);
        if (test_and_clear_bit(In_sync, &rdev->flags)) {
-               unsigned long flags;
-               spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded++;
                set_bit(Faulty, &rdev->flags);
-               spin_unlock_irqrestore(&conf->device_lock, flags);
        } else
                set_bit(Faulty, &rdev->flags);
+       spin_unlock_irqrestore(&conf->device_lock, flags);
        /*
         * if recovery is running, make sure it aborts.
         */
@@ -1567,7 +1568,10 @@ static int raid1_spare_active(struct mddev *mddev)
         * Find all failed disks within the RAID1 configuration
         * and mark them readable.
         * Called under mddev lock, so rcu protection not needed.
+        * device_lock used to avoid races with raid1_end_read_request
+        * which expects 'In_sync' flags and ->degraded to be consistent.
         */
+       spin_lock_irqsave(&conf->device_lock, flags);
        for (i = 0; i < conf->raid_disks; i++) {
                struct md_rdev *rdev = conf->mirrors[i].rdev;
                struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev;
@@ -1598,7 +1602,6 @@ static int raid1_spare_active(struct mddev *mddev)
                        sysfs_notify_dirent_safe(rdev->sysfs_state);
                }
        }
-       spin_lock_irqsave(&conf->device_lock, flags);
        mddev->degraded -= count;
        spin_unlock_irqrestore(&conf->device_lock, flags);
 
index 940f2f3654617918d8eef951262c3ca120ab83ce..38c58e19cfce3d7bdea554b26474080a88e02cca 100644 (file)
@@ -3556,6 +3556,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
                        /* far_copies must be 1 */
                        conf->prev.stride = conf->dev_sectors;
        }
+       conf->reshape_safe = conf->reshape_progress;
        spin_lock_init(&conf->device_lock);
        INIT_LIST_HEAD(&conf->retry_list);
 
@@ -3760,7 +3761,6 @@ static int run(struct mddev *mddev)
                }
                conf->offset_diff = min_offset_diff;
 
-               conf->reshape_safe = conf->reshape_progress;
                clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
                set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
@@ -4103,6 +4103,7 @@ static int raid10_start_reshape(struct mddev *mddev)
                conf->reshape_progress = size;
        } else
                conf->reshape_progress = 0;
+       conf->reshape_safe = conf->reshape_progress;
        spin_unlock_irq(&conf->device_lock);
 
        if (mddev->delta_disks && mddev->bitmap) {
@@ -4170,6 +4171,7 @@ abort:
                rdev->new_data_offset = rdev->data_offset;
        smp_wmb();
        conf->reshape_progress = MaxSector;
+       conf->reshape_safe = MaxSector;
        mddev->reshape_position = MaxSector;
        spin_unlock_irq(&conf->device_lock);
        return ret;
@@ -4524,6 +4526,7 @@ static void end_reshape(struct r10conf *conf)
        md_finish_reshape(conf->mddev);
        smp_wmb();
        conf->reshape_progress = MaxSector;
+       conf->reshape_safe = MaxSector;
        spin_unlock_irq(&conf->device_lock);
 
        /* read-ahead size must cover two whole stripes, which is
index 59e44e99eef3bacd4703fd6883513688f7c58b09..f757023fc4580680bfdd6e178f93acb62cb1f31e 100644 (file)
@@ -2162,6 +2162,9 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        if (!sc)
                return -ENOMEM;
 
+       /* Need to ensure auto-resizing doesn't interfere */
+       mutex_lock(&conf->cache_size_mutex);
+
        for (i = conf->max_nr_stripes; i; i--) {
                nsh = alloc_stripe(sc, GFP_KERNEL);
                if (!nsh)
@@ -2178,6 +2181,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
                        kmem_cache_free(sc, nsh);
                }
                kmem_cache_destroy(sc);
+               mutex_unlock(&conf->cache_size_mutex);
                return -ENOMEM;
        }
        /* Step 2 - Must use GFP_NOIO now.
@@ -2224,6 +2228,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
        } else
                err = -ENOMEM;
 
+       mutex_unlock(&conf->cache_size_mutex);
        /* Step 4, return new stripes to service */
        while(!list_empty(&newstripes)) {
                nsh = list_entry(newstripes.next, struct stripe_head, lru);
@@ -2251,7 +2256,7 @@ static int resize_stripes(struct r5conf *conf, int newsize)
 static int drop_one_stripe(struct r5conf *conf)
 {
        struct stripe_head *sh;
-       int hash = (conf->max_nr_stripes - 1) % NR_STRIPE_HASH_LOCKS;
+       int hash = (conf->max_nr_stripes - 1) & STRIPE_HASH_LOCKS_MASK;
 
        spin_lock_irq(conf->hash_locks + hash);
        sh = get_free_stripe(conf, hash);
@@ -4061,8 +4066,10 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
                                 &first_bad, &bad_sectors))
                        set_bit(R5_ReadRepl, &dev->flags);
                else {
-                       if (rdev)
+                       if (rdev && !test_bit(Faulty, &rdev->flags))
                                set_bit(R5_NeedReplace, &dev->flags);
+                       else
+                               clear_bit(R5_NeedReplace, &dev->flags);
                        rdev = rcu_dereference(conf->disks[i].rdev);
                        clear_bit(R5_ReadRepl, &dev->flags);
                }
@@ -5857,12 +5864,14 @@ static void raid5d(struct md_thread *thread)
        pr_debug("%d stripes handled\n", handled);
 
        spin_unlock_irq(&conf->device_lock);
-       if (test_and_clear_bit(R5_ALLOC_MORE, &conf->cache_state)) {
+       if (test_and_clear_bit(R5_ALLOC_MORE, &conf->cache_state) &&
+           mutex_trylock(&conf->cache_size_mutex)) {
                grow_one_stripe(conf, __GFP_NOWARN);
                /* Set flag even if allocation failed.  This helps
                 * slow down allocation requests when mem is short
                 */
                set_bit(R5_DID_ALLOC, &conf->cache_state);
+               mutex_unlock(&conf->cache_size_mutex);
        }
 
        async_tx_issue_pending_all();
@@ -5894,18 +5903,22 @@ raid5_set_cache_size(struct mddev *mddev, int size)
                return -EINVAL;
 
        conf->min_nr_stripes = size;
+       mutex_lock(&conf->cache_size_mutex);
        while (size < conf->max_nr_stripes &&
               drop_one_stripe(conf))
                ;
+       mutex_unlock(&conf->cache_size_mutex);
 
 
        err = md_allow_write(mddev);
        if (err)
                return err;
 
+       mutex_lock(&conf->cache_size_mutex);
        while (size > conf->max_nr_stripes)
                if (!grow_one_stripe(conf, GFP_KERNEL))
                        break;
+       mutex_unlock(&conf->cache_size_mutex);
 
        return 0;
 }
@@ -6371,11 +6384,19 @@ static unsigned long raid5_cache_scan(struct shrinker *shrink,
                                      struct shrink_control *sc)
 {
        struct r5conf *conf = container_of(shrink, struct r5conf, shrinker);
-       int ret = 0;
-       while (ret < sc->nr_to_scan) {
-               if (drop_one_stripe(conf) == 0)
-                       return SHRINK_STOP;
-               ret++;
+       unsigned long ret = SHRINK_STOP;
+
+       if (mutex_trylock(&conf->cache_size_mutex)) {
+               ret= 0;
+               while (ret < sc->nr_to_scan &&
+                      conf->max_nr_stripes > conf->min_nr_stripes) {
+                       if (drop_one_stripe(conf) == 0) {
+                               ret = SHRINK_STOP;
+                               break;
+                       }
+                       ret++;
+               }
+               mutex_unlock(&conf->cache_size_mutex);
        }
        return ret;
 }
@@ -6444,6 +6465,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
                goto abort;
        spin_lock_init(&conf->device_lock);
        seqcount_init(&conf->gen_lock);
+       mutex_init(&conf->cache_size_mutex);
        init_waitqueue_head(&conf->wait_for_quiescent);
        for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++) {
                init_waitqueue_head(&conf->wait_for_stripe[i]);
index 02c3bf8fbfe7aa1b0a1c568605393dc3769c6b18..d05144278690ca9b8cb4ad933d6d23dc36b9b0f8 100644 (file)
@@ -482,7 +482,8 @@ struct r5conf {
         */
        int                     active_name;
        char                    cache_name[2][32];
-       struct kmem_cache               *slab_cache; /* for allocating stripes */
+       struct kmem_cache       *slab_cache; /* for allocating stripes */
+       struct mutex            cache_size_mutex; /* Protect changes to cache size */
 
        int                     seq_flush, seq_write;
        int                     quiesce;
index 0d35f5850ff1ea8e9910168f55fe04f05c42600e..5ab90f36a6a687c3c64edd56f09d3f8708dba635 100644 (file)
@@ -240,7 +240,7 @@ config DVB_SI21XX
 
 config DVB_TS2020
        tristate "Montage Tehnology TS2020 based tuners"
-       depends on DVB_CORE
+       depends on DVB_CORE && I2C
        select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
index 3be1b2c3c3860ec48c2e9a1e5e5cd41daf56046f..6a1c0089bb6279c6660b6154681c1c7cdeb129d4 100644 (file)
@@ -2,6 +2,7 @@ config VIDEO_COBALT
        tristate "Cisco Cobalt support"
        depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER
        depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB
+       depends on SND
        select I2C_ALGOBIT
        select VIDEO_ADV7604
        select VIDEO_ADV7511
index dd4bff9cf3390a4f167c6e5d1a9ae4886dae9750..d1f5898d11ba1c046737b2bb2a7ba48fa7547b9d 100644 (file)
@@ -139,7 +139,7 @@ done:
           also know about dropped frames. */
        cb->vb.v4l2_buf.sequence = s->sequence++;
        vb2_buffer_done(&cb->vb, (skip || s->unstable_frame) ?
-                       VB2_BUF_STATE_QUEUED : VB2_BUF_STATE_DONE);
+                       VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE);
 }
 
 irqreturn_t cobalt_irq_handler(int irq, void *dev_id)
index 4cb365d4ffdcc9c4e12cde82f46d411cb86c7a13..8b95eefb610b4097787a7363c6e43b94ce260efb 100644 (file)
@@ -38,6 +38,8 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/fb.h>
@@ -1171,6 +1173,13 @@ static int ivtvfb_init_card(struct ivtv *itv)
 {
        int rc;
 
+#ifdef CONFIG_X86_64
+       if (pat_enabled()) {
+               pr_warn("ivtvfb needs PAT disabled, boot with nopat kernel parameter\n");
+               return -ENODEV;
+       }
+#endif
+
        if (itv->osd_info) {
                IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
                return -EBUSY;
@@ -1265,12 +1274,6 @@ static int __init ivtvfb_init(void)
        int registered = 0;
        int err;
 
-#ifdef CONFIG_X86_64
-       if (WARN(pat_enabled(),
-                "ivtvfb needs PAT disabled, boot with nopat kernel parameter\n")) {
-               return -ENODEV;
-       }
-#endif
 
        if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
                printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
index 1d59c7e039f7d41e989dc986cf6ac09815165747..87990ece5848957baf4af40dd5100f356466b901 100644 (file)
@@ -130,10 +130,11 @@ err:
 
 int mantis_dma_init(struct mantis_pci *mantis)
 {
-       int err = 0;
+       int err;
 
        dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
-       if (mantis_alloc_buffers(mantis) < 0) {
+       err = mantis_alloc_buffers(mantis);
+       if (err < 0) {
                dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
 
                /* Stop RISC Engine */
index 8939ebd7439198161935f573652f25babb438840..84fa6e9b59a1acd9360364fbd30ca0a4e00d3a56 100644 (file)
@@ -184,125 +184,9 @@ out:
        return -EINVAL;
 }
 
-static struct ir_raw_timings_manchester ir_rc5_timings = {
-       .leader                 = RC5_UNIT,
-       .pulse_space_start      = 0,
-       .clock                  = RC5_UNIT,
-       .trailer_space          = RC5_UNIT * 10,
-};
-
-static struct ir_raw_timings_manchester ir_rc5x_timings[2] = {
-       {
-               .leader                 = RC5_UNIT,
-               .pulse_space_start      = 0,
-               .clock                  = RC5_UNIT,
-               .trailer_space          = RC5X_SPACE,
-       },
-       {
-               .clock                  = RC5_UNIT,
-               .trailer_space          = RC5_UNIT * 10,
-       },
-};
-
-static struct ir_raw_timings_manchester ir_rc5_sz_timings = {
-       .leader                         = RC5_UNIT,
-       .pulse_space_start              = 0,
-       .clock                          = RC5_UNIT,
-       .trailer_space                  = RC5_UNIT * 10,
-};
-
-static int ir_rc5_validate_filter(const struct rc_scancode_filter *scancode,
-                                 unsigned int important_bits)
-{
-       /* all important bits of scancode should be set in mask */
-       if (~scancode->mask & important_bits)
-               return -EINVAL;
-       /* extra bits in mask should be zero in data */
-       if (scancode->mask & scancode->data & ~important_bits)
-               return -EINVAL;
-       return 0;
-}
-
-/**
- * ir_rc5_encode() - Encode a scancode as a stream of raw events
- *
- * @protocols: allowed protocols
- * @scancode:  scancode filter describing scancode (helps distinguish between
- *             protocol subtypes when scancode is ambiguous)
- * @events:    array of raw ir events to write into
- * @max:       maximum size of @events
- *
- * Returns:    The number of events written.
- *             -ENOBUFS if there isn't enough space in the array to fit the
- *             encoding. In this case all @max events will have been written.
- *             -EINVAL if the scancode is ambiguous or invalid.
- */
-static int ir_rc5_encode(u64 protocols,
-                        const struct rc_scancode_filter *scancode,
-                        struct ir_raw_event *events, unsigned int max)
-{
-       int ret;
-       struct ir_raw_event *e = events;
-       unsigned int data, xdata, command, commandx, system;
-
-       /* Detect protocol and convert scancode to raw data */
-       if (protocols & RC_BIT_RC5 &&
-           !ir_rc5_validate_filter(scancode, 0x1f7f)) {
-               /* decode scancode */
-               command  = (scancode->data & 0x003f) >> 0;
-               commandx = (scancode->data & 0x0040) >> 6;
-               system   = (scancode->data & 0x1f00) >> 8;
-               /* encode data */
-               data = !commandx << 12 | system << 6 | command;
-
-               /* Modulate the data */
-               ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings, RC5_NBITS,
-                                           data);
-               if (ret < 0)
-                       return ret;
-       } else if (protocols & RC_BIT_RC5X &&
-                  !ir_rc5_validate_filter(scancode, 0x1f7f3f)) {
-               /* decode scancode */
-               xdata    = (scancode->data & 0x00003f) >> 0;
-               command  = (scancode->data & 0x003f00) >> 8;
-               commandx = (scancode->data & 0x004000) >> 14;
-               system   = (scancode->data & 0x1f0000) >> 16;
-               /* commandx and system overlap, bits must match when encoded */
-               if (commandx == (system & 0x1))
-                       return -EINVAL;
-               /* encode data */
-               data = 1 << 18 | system << 12 | command << 6 | xdata;
-
-               /* Modulate the data */
-               ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
-                                       CHECK_RC5X_NBITS,
-                                       data >> (RC5X_NBITS-CHECK_RC5X_NBITS));
-               if (ret < 0)
-                       return ret;
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                       &ir_rc5x_timings[1],
-                                       RC5X_NBITS - CHECK_RC5X_NBITS,
-                                       data);
-               if (ret < 0)
-                       return ret;
-       } else if (protocols & RC_BIT_RC5_SZ &&
-                  !ir_rc5_validate_filter(scancode, 0x2fff)) {
-               /* RC5-SZ scancode is raw enough for Manchester as it is */
-               ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings,
-                                       RC5_SZ_NBITS, scancode->data & 0x2fff);
-               if (ret < 0)
-                       return ret;
-       } else {
-               return -EINVAL;
-       }
-
-       return e - events;
-}
-
 static struct ir_raw_handler rc5_handler = {
        .protocols      = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
        .decode         = ir_rc5_decode,
-       .encode         = ir_rc5_encode,
 };
 
 static int __init ir_rc5_decode_init(void)
index f9c70baf6e0cb1f071f0a6f7e2ac9e81cf131817..d16bc67af732251998fb280b86d887835cf39e1b 100644 (file)
@@ -291,133 +291,11 @@ out:
        return -EINVAL;
 }
 
-static struct ir_raw_timings_manchester ir_rc6_timings[4] = {
-       {
-               .leader                 = RC6_PREFIX_PULSE,
-               .pulse_space_start      = 0,
-               .clock                  = RC6_UNIT,
-               .invert                 = 1,
-               .trailer_space          = RC6_PREFIX_SPACE,
-       },
-       {
-               .clock                  = RC6_UNIT,
-               .invert                 = 1,
-       },
-       {
-               .clock                  = RC6_UNIT * 2,
-               .invert                 = 1,
-       },
-       {
-               .clock                  = RC6_UNIT,
-               .invert                 = 1,
-               .trailer_space          = RC6_SUFFIX_SPACE,
-       },
-};
-
-static int ir_rc6_validate_filter(const struct rc_scancode_filter *scancode,
-                                 unsigned int important_bits)
-{
-       /* all important bits of scancode should be set in mask */
-       if (~scancode->mask & important_bits)
-               return -EINVAL;
-       /* extra bits in mask should be zero in data */
-       if (scancode->mask & scancode->data & ~important_bits)
-               return -EINVAL;
-       return 0;
-}
-
-/**
- * ir_rc6_encode() - Encode a scancode as a stream of raw events
- *
- * @protocols: allowed protocols
- * @scancode:  scancode filter describing scancode (helps distinguish between
- *             protocol subtypes when scancode is ambiguous)
- * @events:    array of raw ir events to write into
- * @max:       maximum size of @events
- *
- * Returns:    The number of events written.
- *             -ENOBUFS if there isn't enough space in the array to fit the
- *             encoding. In this case all @max events will have been written.
- *             -EINVAL if the scancode is ambiguous or invalid.
- */
-static int ir_rc6_encode(u64 protocols,
-                        const struct rc_scancode_filter *scancode,
-                        struct ir_raw_event *events, unsigned int max)
-{
-       int ret;
-       struct ir_raw_event *e = events;
-
-       if (protocols & RC_BIT_RC6_0 &&
-           !ir_rc6_validate_filter(scancode, 0xffff)) {
-
-               /* Modulate the preamble */
-               ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
-               if (ret < 0)
-                       return ret;
-
-               /* Modulate the header (Start Bit & Mode-0) */
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                           &ir_rc6_timings[1],
-                                           RC6_HEADER_NBITS, (1 << 3));
-               if (ret < 0)
-                       return ret;
-
-               /* Modulate Trailer Bit */
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                           &ir_rc6_timings[2], 1, 0);
-               if (ret < 0)
-                       return ret;
-
-               /* Modulate rest of the data */
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                           &ir_rc6_timings[3], RC6_0_NBITS,
-                                           scancode->data);
-               if (ret < 0)
-                       return ret;
-
-       } else if (protocols & (RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
-                               RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE) &&
-                  !ir_rc6_validate_filter(scancode, 0x8fffffff)) {
-
-               /* Modulate the preamble */
-               ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
-               if (ret < 0)
-                       return ret;
-
-               /* Modulate the header (Start Bit & Header-version 6 */
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                           &ir_rc6_timings[1],
-                                           RC6_HEADER_NBITS, (1 << 3 | 6));
-               if (ret < 0)
-                       return ret;
-
-               /* Modulate Trailer Bit */
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                           &ir_rc6_timings[2], 1, 0);
-               if (ret < 0)
-                       return ret;
-
-               /* Modulate rest of the data */
-               ret = ir_raw_gen_manchester(&e, max - (e - events),
-                                           &ir_rc6_timings[3],
-                                           fls(scancode->mask),
-                                           scancode->data);
-               if (ret < 0)
-                       return ret;
-
-       } else {
-               return -EINVAL;
-       }
-
-       return e - events;
-}
-
 static struct ir_raw_handler rc6_handler = {
        .protocols      = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
                          RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
                          RC_BIT_RC6_MCE,
        .decode         = ir_rc6_decode,
-       .encode         = ir_rc6_encode,
 };
 
 static int __init ir_rc6_decode_init(void)
index baeb5971fd52cecca1a01f436713f9f3a77c65ca..85af7a8691677a9b3965f469f37bc49b741de6b7 100644 (file)
@@ -526,130 +526,6 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
        return 0;
 }
 
-static int nvt_write_wakeup_codes(struct rc_dev *dev,
-                                 const u8 *wakeup_sample_buf, int count)
-{
-       int i = 0;
-       u8 reg, reg_learn_mode;
-       unsigned long flags;
-       struct nvt_dev *nvt = dev->priv;
-
-       nvt_dbg_wake("writing wakeup samples");
-
-       reg = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
-       reg_learn_mode = reg & ~CIR_WAKE_IRCON_MODE0;
-       reg_learn_mode |= CIR_WAKE_IRCON_MODE1;
-
-       /* Lock the learn area to prevent racing with wake-isr */
-       spin_lock_irqsave(&nvt->nvt_lock, flags);
-
-       /* Enable fifo writes */
-       nvt_cir_wake_reg_write(nvt, reg_learn_mode, CIR_WAKE_IRCON);
-
-       /* Clear cir wake rx fifo */
-       nvt_clear_cir_wake_fifo(nvt);
-
-       if (count > WAKE_FIFO_LEN) {
-               nvt_dbg_wake("HW FIFO too small for all wake samples");
-               count = WAKE_FIFO_LEN;
-       }
-
-       if (count)
-               pr_info("Wake samples (%d) =", count);
-       else
-               pr_info("Wake sample fifo cleared");
-
-       /* Write wake samples to fifo */
-       for (i = 0; i < count; i++) {
-               pr_cont(" %02x", wakeup_sample_buf[i]);
-               nvt_cir_wake_reg_write(nvt, wakeup_sample_buf[i],
-                                      CIR_WAKE_WR_FIFO_DATA);
-       }
-       pr_cont("\n");
-
-       /* Switch cir to wakeup mode and disable fifo writing */
-       nvt_cir_wake_reg_write(nvt, reg, CIR_WAKE_IRCON);
-
-       /* Set number of bytes needed for wake */
-       nvt_cir_wake_reg_write(nvt, count ? count :
-                              CIR_WAKE_FIFO_CMP_BYTES,
-                              CIR_WAKE_FIFO_CMP_DEEP);
-
-       spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
-       return 0;
-}
-
-static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
-                                       struct rc_scancode_filter *sc_filter)
-{
-       u8 *reg_buf;
-       u8 buf_val;
-       int i, ret, count;
-       unsigned int val;
-       struct ir_raw_event *raw;
-       bool complete;
-
-       /* Require both mask and data to be set before actually committing */
-       if (!sc_filter->mask || !sc_filter->data)
-               return 0;
-
-       raw = kmalloc_array(WAKE_FIFO_LEN, sizeof(*raw), GFP_KERNEL);
-       if (!raw)
-               return -ENOMEM;
-
-       ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter,
-                                    raw, WAKE_FIFO_LEN);
-       complete = (ret != -ENOBUFS);
-       if (!complete)
-               ret = WAKE_FIFO_LEN;
-       else if (ret < 0)
-               goto out_raw;
-
-       reg_buf = kmalloc_array(WAKE_FIFO_LEN, sizeof(*reg_buf), GFP_KERNEL);
-       if (!reg_buf) {
-               ret = -ENOMEM;
-               goto out_raw;
-       }
-
-       /* Inspect the ir samples */
-       for (i = 0, count = 0; i < ret && count < WAKE_FIFO_LEN; ++i) {
-               val = NS_TO_US((raw[i]).duration) / SAMPLE_PERIOD;
-
-               /* Split too large values into several smaller ones */
-               while (val > 0 && count < WAKE_FIFO_LEN) {
-
-                       /* Skip last value for better comparison tolerance */
-                       if (complete && i == ret - 1 && val < BUF_LEN_MASK)
-                               break;
-
-                       /* Clamp values to BUF_LEN_MASK at most */
-                       buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val;
-
-                       reg_buf[count] = buf_val;
-                       val -= buf_val;
-                       if ((raw[i]).pulse)
-                               reg_buf[count] |= BUF_PULSE_BIT;
-                       count++;
-               }
-       }
-
-       ret = nvt_write_wakeup_codes(dev, reg_buf, count);
-
-       kfree(reg_buf);
-out_raw:
-       kfree(raw);
-
-       return ret;
-}
-
-/* Dummy implementation. nuvoton is agnostic to the protocol used */
-static int nvt_ir_raw_change_wakeup_protocol(struct rc_dev *dev,
-                                            u64 *rc_type)
-{
-       return 0;
-}
-
 /*
  * nvt_tx_ir
  *
@@ -1167,14 +1043,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
        /* Set up the rc device */
        rdev->priv = nvt;
        rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->encode_wakeup = true;
        rdev->allowed_protocols = RC_BIT_ALL;
        rdev->open = nvt_open;
        rdev->close = nvt_close;
        rdev->tx_ir = nvt_tx_ir;
        rdev->s_tx_carrier = nvt_set_tx_carrier;
-       rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter;
-       rdev->change_wakeup_protocol = nvt_ir_raw_change_wakeup_protocol;
        rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
        rdev->input_phys = "nuvoton/cir0";
        rdev->input_id.bustype = BUS_HOST;
index 9d0e161c2a886c511d3fde3928b154b0cfb7f0db..e1cf23c3875b16ead52464d4e6ad3c479fd1e951 100644 (file)
@@ -63,7 +63,6 @@ static int debug;
  */
 #define TX_BUF_LEN 256
 #define RX_BUF_LEN 32
-#define WAKE_FIFO_LEN 67
 
 struct nvt_dev {
        struct pnp_dev *pdev;
index 4b994aa2f2a7d1f763fd5bb7eccfb95f8ba1b6d6..b68d4f76273448fcbc98fc1e215a6656c9b6c6ec 100644 (file)
@@ -25,8 +25,6 @@ struct ir_raw_handler {
 
        u64 protocols; /* which are handled by this handler */
        int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
-       int (*encode)(u64 protocols, const struct rc_scancode_filter *scancode,
-                     struct ir_raw_event *events, unsigned int max);
 
        /* These two should only be used by the lirc decoder */
        int (*raw_register)(struct rc_dev *dev);
@@ -152,44 +150,10 @@ static inline bool is_timing_event(struct ir_raw_event ev)
 #define TO_US(duration)                        DIV_ROUND_CLOSEST((duration), 1000)
 #define TO_STR(is_pulse)               ((is_pulse) ? "pulse" : "space")
 
-/* functions for IR encoders */
-
-static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
-                                             unsigned int pulse,
-                                             u32 duration)
-{
-       init_ir_raw_event(ev);
-       ev->duration = duration;
-       ev->pulse = pulse;
-}
-
-/**
- * struct ir_raw_timings_manchester - Manchester coding timings
- * @leader:            duration of leader pulse (if any) 0 if continuing
- *                     existing signal (see @pulse_space_start)
- * @pulse_space_start: 1 for starting with pulse (0 for starting with space)
- * @clock:             duration of each pulse/space in ns
- * @invert:            if set clock logic is inverted
- *                     (0 = space + pulse, 1 = pulse + space)
- * @trailer_space:     duration of trailer space in ns
- */
-struct ir_raw_timings_manchester {
-       unsigned int leader;
-       unsigned int pulse_space_start:1;
-       unsigned int clock;
-       unsigned int invert:1;
-       unsigned int trailer_space;
-};
-
-int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
-                         const struct ir_raw_timings_manchester *timings,
-                         unsigned int n, unsigned int data);
-
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
 u64 ir_raw_get_allowed_protocols(void);
-u64 ir_raw_get_encode_protocols(void);
 int ir_raw_event_register(struct rc_dev *dev);
 void ir_raw_event_unregister(struct rc_dev *dev);
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
index b9e4645c731c087f3dea99fa652fe09ef19dc8de..b732ac6a26d8065cc26ecb3a648ced999db71367 100644 (file)
@@ -30,7 +30,6 @@ static LIST_HEAD(ir_raw_client_list);
 static DEFINE_MUTEX(ir_raw_handler_lock);
 static LIST_HEAD(ir_raw_handler_list);
 static u64 available_protocols;
-static u64 encode_protocols;
 
 static int ir_raw_event_thread(void *data)
 {
@@ -241,146 +240,12 @@ ir_raw_get_allowed_protocols(void)
        return protocols;
 }
 
-/* used internally by the sysfs interface */
-u64
-ir_raw_get_encode_protocols(void)
-{
-       u64 protocols;
-
-       mutex_lock(&ir_raw_handler_lock);
-       protocols = encode_protocols;
-       mutex_unlock(&ir_raw_handler_lock);
-       return protocols;
-}
-
 static int change_protocol(struct rc_dev *dev, u64 *rc_type)
 {
        /* the caller will update dev->enabled_protocols */
        return 0;
 }
 
-/**
- * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
- * @ev:                Pointer to pointer to next free event. *@ev is incremented for
- *             each raw event filled.
- * @max:       Maximum number of raw events to fill.
- * @timings:   Manchester modulation timings.
- * @n:         Number of bits of data.
- * @data:      Data bits to encode.
- *
- * Encodes the @n least significant bits of @data using Manchester (bi-phase)
- * modulation with the timing characteristics described by @timings, writing up
- * to @max raw IR events using the *@ev pointer.
- *
- * Returns:    0 on success.
- *             -ENOBUFS if there isn't enough space in the array to fit the
- *             full encoded data. In this case all @max events will have been
- *             written.
- */
-int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
-                         const struct ir_raw_timings_manchester *timings,
-                         unsigned int n, unsigned int data)
-{
-       bool need_pulse;
-       unsigned int i;
-       int ret = -ENOBUFS;
-
-       i = 1 << (n - 1);
-
-       if (timings->leader) {
-               if (!max--)
-                       return ret;
-               if (timings->pulse_space_start) {
-                       init_ir_raw_event_duration((*ev)++, 1, timings->leader);
-
-                       if (!max--)
-                               return ret;
-                       init_ir_raw_event_duration((*ev), 0, timings->leader);
-               } else {
-                       init_ir_raw_event_duration((*ev), 1, timings->leader);
-               }
-               i >>= 1;
-       } else {
-               /* continue existing signal */
-               --(*ev);
-       }
-       /* from here on *ev will point to the last event rather than the next */
-
-       while (n && i > 0) {
-               need_pulse = !(data & i);
-               if (timings->invert)
-                       need_pulse = !need_pulse;
-               if (need_pulse == !!(*ev)->pulse) {
-                       (*ev)->duration += timings->clock;
-               } else {
-                       if (!max--)
-                               goto nobufs;
-                       init_ir_raw_event_duration(++(*ev), need_pulse,
-                                                  timings->clock);
-               }
-
-               if (!max--)
-                       goto nobufs;
-               init_ir_raw_event_duration(++(*ev), !need_pulse,
-                                          timings->clock);
-               i >>= 1;
-       }
-
-       if (timings->trailer_space) {
-               if (!(*ev)->pulse)
-                       (*ev)->duration += timings->trailer_space;
-               else if (!max--)
-                       goto nobufs;
-               else
-                       init_ir_raw_event_duration(++(*ev), 0,
-                                                  timings->trailer_space);
-       }
-
-       ret = 0;
-nobufs:
-       /* point to the next event rather than last event before returning */
-       ++(*ev);
-       return ret;
-}
-EXPORT_SYMBOL(ir_raw_gen_manchester);
-
-/**
- * ir_raw_encode_scancode() - Encode a scancode as raw events
- *
- * @protocols:         permitted protocols
- * @scancode:          scancode filter describing a single scancode
- * @events:            array of raw events to write into
- * @max:               max number of raw events
- *
- * Attempts to encode the scancode as raw events.
- *
- * Returns:    The number of events written.
- *             -ENOBUFS if there isn't enough space in the array to fit the
- *             encoding. In this case all @max events will have been written.
- *             -EINVAL if the scancode is ambiguous or invalid, or if no
- *             compatible encoder was found.
- */
-int ir_raw_encode_scancode(u64 protocols,
-                          const struct rc_scancode_filter *scancode,
-                          struct ir_raw_event *events, unsigned int max)
-{
-       struct ir_raw_handler *handler;
-       int ret = -EINVAL;
-
-       mutex_lock(&ir_raw_handler_lock);
-       list_for_each_entry(handler, &ir_raw_handler_list, list) {
-               if (handler->protocols & protocols && handler->encode) {
-                       ret = handler->encode(protocols, scancode, events, max);
-                       if (ret >= 0 || ret == -ENOBUFS)
-                               break;
-               }
-       }
-       mutex_unlock(&ir_raw_handler_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(ir_raw_encode_scancode);
-
 /*
  * Used to (un)register raw event clients
  */
@@ -463,8 +328,6 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
                list_for_each_entry(raw, &ir_raw_client_list, list)
                        ir_raw_handler->raw_register(raw->dev);
        available_protocols |= ir_raw_handler->protocols;
-       if (ir_raw_handler->encode)
-               encode_protocols |= ir_raw_handler->protocols;
        mutex_unlock(&ir_raw_handler_lock);
 
        return 0;
@@ -481,8 +344,6 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
                list_for_each_entry(raw, &ir_raw_client_list, list)
                        ir_raw_handler->raw_unregister(raw->dev);
        available_protocols &= ~ir_raw_handler->protocols;
-       if (ir_raw_handler->encode)
-               encode_protocols &= ~ir_raw_handler->protocols;
        mutex_unlock(&ir_raw_handler_lock);
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
index d8bdf63ce9858ccfc78536fc698698e16c751670..63dace8198b0b3dbcb116108e238351fe9684a9e 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <linux/slab.h>
 #include <media/rc-core.h>
 
 #define DRIVER_NAME    "rc-loopback"
@@ -177,39 +176,6 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
        return 0;
 }
 
-static int loop_set_wakeup_filter(struct rc_dev *dev,
-                                 struct rc_scancode_filter *sc_filter)
-{
-       static const unsigned int max = 512;
-       struct ir_raw_event *raw;
-       int ret;
-       int i;
-
-       /* fine to disable filter */
-       if (!sc_filter->mask)
-               return 0;
-
-       /* encode the specified filter and loop it back */
-       raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL);
-       ret = ir_raw_encode_scancode(dev->enabled_wakeup_protocols, sc_filter,
-                                    raw, max);
-       /* still loop back the partial raw IR even if it's incomplete */
-       if (ret == -ENOBUFS)
-               ret = max;
-       if (ret >= 0) {
-               /* do the loopback */
-               for (i = 0; i < ret; ++i)
-                       ir_raw_event_store(dev, &raw[i]);
-               ir_raw_event_handle(dev);
-
-               ret = 0;
-       }
-
-       kfree(raw);
-
-       return ret;
-}
-
 static int __init loop_init(void)
 {
        struct rc_dev *rc;
@@ -229,7 +195,6 @@ static int __init loop_init(void)
        rc->map_name            = RC_MAP_EMPTY;
        rc->priv                = &loopdev;
        rc->driver_type         = RC_DRIVER_IR_RAW;
-       rc->encode_wakeup       = true;
        rc->allowed_protocols   = RC_BIT_ALL;
        rc->timeout             = 100 * 1000 * 1000; /* 100 ms */
        rc->min_timeout         = 1;
@@ -244,7 +209,6 @@ static int __init loop_init(void)
        rc->s_idle              = loop_set_idle;
        rc->s_learning_mode     = loop_set_learning_mode;
        rc->s_carrier_report    = loop_set_carrier_report;
-       rc->s_wakeup_filter     = loop_set_wakeup_filter;
 
        loopdev.txmask          = RXMASK_REGULAR;
        loopdev.txcarrier       = 36000;
index 9d015db652808fcb54fc0abfff19e9018dbad488..0ff388a1616876d50ade807ff5bff20204d1b8cd 100644 (file)
@@ -865,8 +865,6 @@ static ssize_t show_protocols(struct device *device,
        } else {
                enabled = dev->enabled_wakeup_protocols;
                allowed = dev->allowed_wakeup_protocols;
-               if (dev->encode_wakeup && !allowed)
-                       allowed = ir_raw_get_encode_protocols();
        }
 
        mutex_unlock(&dev->lock);
@@ -1408,16 +1406,13 @@ int rc_register_device(struct rc_dev *dev)
                path ? path : "N/A");
        kfree(path);
 
-       if (dev->driver_type == RC_DRIVER_IR_RAW || dev->encode_wakeup) {
+       if (dev->driver_type == RC_DRIVER_IR_RAW) {
                /* Load raw decoders, if they aren't already */
                if (!raw_init) {
                        IR_dprintk(1, "Loading raw decoders\n");
                        ir_raw_init();
                        raw_init = true;
                }
-       }
-
-       if (dev->driver_type == RC_DRIVER_IR_RAW) {
                /* calls ir_register_device so unlock mutex here*/
                mutex_unlock(&dev->lock);
                rc = ir_raw_event_register(dev);
index 93b315459098932381d61d282cdb3f04194b18ae..a14c428f70e992460ed869b492723a5a08f155b9 100644 (file)
@@ -715,6 +715,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
                break;
        case VB2_BUF_STATE_PREPARING:
        case VB2_BUF_STATE_DEQUEUED:
+       case VB2_BUF_STATE_REQUEUEING:
                /* nothing */
                break;
        }
@@ -1182,7 +1183,8 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
 
        if (WARN_ON(state != VB2_BUF_STATE_DONE &&
                    state != VB2_BUF_STATE_ERROR &&
-                   state != VB2_BUF_STATE_QUEUED))
+                   state != VB2_BUF_STATE_QUEUED &&
+                   state != VB2_BUF_STATE_REQUEUEING))
                state = VB2_BUF_STATE_ERROR;
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1199,22 +1201,30 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
        for (plane = 0; plane < vb->num_planes; ++plane)
                call_void_memop(vb, finish, vb->planes[plane].mem_priv);
 
-       /* Add the buffer to the done buffers list */
        spin_lock_irqsave(&q->done_lock, flags);
-       vb->state = state;
-       if (state != VB2_BUF_STATE_QUEUED)
+       if (state == VB2_BUF_STATE_QUEUED ||
+           state == VB2_BUF_STATE_REQUEUEING) {
+               vb->state = VB2_BUF_STATE_QUEUED;
+       } else {
+               /* Add the buffer to the done buffers list */
                list_add_tail(&vb->done_entry, &q->done_list);
+               vb->state = state;
+       }
        atomic_dec(&q->owned_by_drv_count);
        spin_unlock_irqrestore(&q->done_lock, flags);
 
-       if (state == VB2_BUF_STATE_QUEUED) {
+       switch (state) {
+       case VB2_BUF_STATE_QUEUED:
+               return;
+       case VB2_BUF_STATE_REQUEUEING:
                if (q->start_streaming_called)
                        __enqueue_in_driver(vb);
                return;
+       default:
+               /* Inform any processes that may be waiting for buffers */
+               wake_up(&q->done_wq);
+               break;
        }
-
-       /* Inform any processes that may be waiting for buffers */
-       wake_up(&q->done_wq);
 }
 EXPORT_SYMBOL_GPL(vb2_buffer_done);
 
@@ -1244,19 +1254,19 @@ EXPORT_SYMBOL_GPL(vb2_discard_done);
 
 static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
 {
-       static bool __check_once __read_mostly;
+       static bool check_once;
 
-       if (__check_once)
+       if (check_once)
                return;
 
-       __check_once = true;
-       __WARN();
+       check_once = true;
+       WARN_ON(1);
 
-       pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n");
+       pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n");
        if (vb->vb2_queue->allow_zero_bytesused)
-               pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
+               pr_warn("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n");
        else
-               pr_warn_once("use the actual size instead.\n");
+               pr_warn("use the actual size instead.\n");
 }
 
 /**
index 8911e51d410ab3c6e8d14af25fb5c1ff7751b47d..9426276dbe1402b1445dd7b84da6d7fca38893a6 100644 (file)
@@ -2074,14 +2074,8 @@ static int gpmc_probe_dt(struct platform_device *pdev)
                        ret = gpmc_probe_nand_child(pdev, child);
                else if (of_node_cmp(child->name, "onenand") == 0)
                        ret = gpmc_probe_onenand_child(pdev, child);
-               else if (of_node_cmp(child->name, "ethernet") == 0 ||
-                        of_node_cmp(child->name, "nor") == 0 ||
-                        of_node_cmp(child->name, "uart") == 0)
+               else
                        ret = gpmc_probe_generic_child(pdev, child);
-
-               if (WARN(ret < 0, "%s: probing gpmc child %s failed\n",
-                        __func__, child->full_name))
-                       of_node_put(child);
        }
 
        return 0;
@@ -2251,6 +2245,9 @@ void omap3_gpmc_save_context(void)
 {
        int i;
 
+       if (!gpmc_base)
+               return;
+
        gpmc_context.sysconfig = gpmc_read_reg(GPMC_SYSCONFIG);
        gpmc_context.irqenable = gpmc_read_reg(GPMC_IRQENABLE);
        gpmc_context.timeout_ctrl = gpmc_read_reg(GPMC_TIMEOUT_CONTROL);
@@ -2283,6 +2280,9 @@ void omap3_gpmc_restore_context(void)
 {
        int i;
 
+       if (!gpmc_base)
+               return;
+
        gpmc_write_reg(GPMC_SYSCONFIG, gpmc_context.sysconfig);
        gpmc_write_reg(GPMC_IRQENABLE, gpmc_context.irqenable);
        gpmc_write_reg(GPMC_TIMEOUT_CONTROL, gpmc_context.timeout_ctrl);
index 653815950aa2416b277718df69213545573aa557..3f68dd251ce89304bf044960568c58c11aca8fdd 100644 (file)
@@ -115,7 +115,7 @@ config MFD_CROS_EC_I2C
 
 config MFD_CROS_EC_SPI
        tristate "ChromeOS Embedded Controller (SPI)"
-       depends on MFD_CROS_EC && CROS_EC_PROTO && SPI && OF
+       depends on MFD_CROS_EC && CROS_EC_PROTO && SPI
 
        ---help---
          If you say Y here, you get support for talking to the ChromeOS EC
index bebf58a06a6b2932d57798c0b5b81a31a12e9b7a..a72ddb2950784cf044fbfb5156ebd68866bbea48 100644 (file)
@@ -651,7 +651,7 @@ static int arizona_runtime_suspend(struct device *dev)
 
                arizona->has_fully_powered_off = true;
 
-               disable_irq(arizona->irq);
+               disable_irq_nosync(arizona->irq);
                arizona_enable_reset(arizona);
                regulator_bulk_disable(arizona->num_core_supplies,
                                       arizona->core_supplies);
@@ -1141,10 +1141,6 @@ int arizona_dev_init(struct arizona *arizona)
                             arizona->pdata.gpio_defaults[i]);
        }
 
-       pm_runtime_set_autosuspend_delay(arizona->dev, 100);
-       pm_runtime_use_autosuspend(arizona->dev);
-       pm_runtime_enable(arizona->dev);
-
        /* Chip default */
        if (!arizona->pdata.clk32k_src)
                arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
@@ -1245,11 +1241,17 @@ int arizona_dev_init(struct arizona *arizona)
                                           arizona->pdata.spk_fmt[i]);
        }
 
+       pm_runtime_set_active(arizona->dev);
+       pm_runtime_enable(arizona->dev);
+
        /* Set up for interrupts */
        ret = arizona_irq_init(arizona);
        if (ret != 0)
                goto err_reset;
 
+       pm_runtime_set_autosuspend_delay(arizona->dev, 100);
+       pm_runtime_use_autosuspend(arizona->dev);
+
        arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
                            arizona_clkgen_err, arizona);
        arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
@@ -1278,10 +1280,6 @@ int arizona_dev_init(struct arizona *arizona)
                goto err_irq;
        }
 
-#ifdef CONFIG_PM
-       regulator_disable(arizona->dcvdd);
-#endif
-
        return 0;
 
 err_irq:
index 5c054031c3f86a80a1aee942f395e56efc8f6b36..e14c8c9d189ba7dfbd20d3623df79f847ed3e9f7 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License Terms: GNU General Public License, version 2
  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * Author: Viresh Kumar <viresh.linux@gmail.com> for ST Microelectronics
+ * Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics
  */
 
 #include <linux/i2c.h>
index a81badbaa917dac49260ae1e10c7b08ec0b1a524..6fdb30e84a2bb932bfa0b3650f179a962e98b9cc 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) ST Microelectronics SA 2011
  *
  * License Terms: GNU General Public License, version 2
- * Author: Viresh Kumar <viresh.linux@gmail.com> for ST Microelectronics
+ * Author: Viresh Kumar <vireshk@kernel.org> for ST Microelectronics
  */
 
 #include <linux/spi/spi.h>
@@ -146,4 +146,4 @@ module_exit(stmpe_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver");
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
index 0c77240ae2fce8cbb832388c20f294f49763e03e..729e0851167df9d441a5d26b34256029dd6db3c8 100644 (file)
@@ -23,6 +23,7 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
 
        afu = cxl_pci_to_afu(dev);
 
+       get_device(&afu->dev);
        ctx = cxl_context_alloc();
        if (IS_ERR(ctx))
                return ctx;
@@ -31,6 +32,7 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev)
        rc = cxl_context_init(ctx, afu, false, NULL);
        if (rc) {
                kfree(ctx);
+               put_device(&afu->dev);
                return ERR_PTR(-ENOMEM);
        }
        cxl_assign_psn_space(ctx);
@@ -60,6 +62,8 @@ int cxl_release_context(struct cxl_context *ctx)
        if (ctx->status != CLOSED)
                return -EBUSY;
 
+       put_device(&ctx->afu->dev);
+
        cxl_context_free(ctx);
 
        return 0;
@@ -159,7 +163,6 @@ int cxl_start_context(struct cxl_context *ctx, u64 wed,
        }
 
        ctx->status = STARTED;
-       get_device(&ctx->afu->dev);
 out:
        mutex_unlock(&ctx->status_mutex);
        return rc;
@@ -175,12 +178,7 @@ EXPORT_SYMBOL_GPL(cxl_process_element);
 /* Stop a context.  Returns 0 on success, otherwise -Errno */
 int cxl_stop_context(struct cxl_context *ctx)
 {
-       int rc;
-
-       rc = __detach_context(ctx);
-       if (!rc)
-               put_device(&ctx->afu->dev);
-       return rc;
+       return __detach_context(ctx);
 }
 EXPORT_SYMBOL_GPL(cxl_stop_context);
 
index 2a4c80ac322ad2500a13fc6162d8920ac4a6b8db..1287148629c0d6f0b6e6066d4c883d8dfaebf9da 100644 (file)
@@ -113,11 +113,11 @@ static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        if (ctx->afu->current_mode == CXL_MODE_DEDICATED) {
                area = ctx->afu->psn_phys;
-               if (offset > ctx->afu->adapter->ps_size)
+               if (offset >= ctx->afu->adapter->ps_size)
                        return VM_FAULT_SIGBUS;
        } else {
                area = ctx->psn_phys;
-               if (offset > ctx->psn_size)
+               if (offset >= ctx->psn_size)
                        return VM_FAULT_SIGBUS;
        }
 
@@ -145,8 +145,16 @@ static const struct vm_operations_struct cxl_mmap_vmops = {
  */
 int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma)
 {
+       u64 start = vma->vm_pgoff << PAGE_SHIFT;
        u64 len = vma->vm_end - vma->vm_start;
-       len = min(len, ctx->psn_size);
+
+       if (ctx->afu->current_mode == CXL_MODE_DEDICATED) {
+               if (start + len > ctx->afu->adapter->ps_size)
+                       return -EINVAL;
+       } else {
+               if (start + len > ctx->psn_size)
+                       return -EINVAL;
+       }
 
        if (ctx->afu->current_mode != CXL_MODE_DEDICATED) {
                /* make sure there is a valid per process space for this AFU */
index 833348e2c9cbc161128d2666f0329e4b18ea536b..4a164ab8b35a65d864c1d83ebe72312624b15c4c 100644 (file)
@@ -73,7 +73,7 @@ static inline void cxl_slbia_core(struct mm_struct *mm)
                spin_lock(&adapter->afu_list_lock);
                for (slice = 0; slice < adapter->slices; slice++) {
                        afu = adapter->afu[slice];
-                       if (!afu->enabled)
+                       if (!afu || !afu->enabled)
                                continue;
                        rcu_read_lock();
                        idr_for_each_entry(&afu->contexts_idr, ctx, id)
index c68ef5806dbe122503742f57c6d1259a599b7cf7..32ad097059498c4d5b6f8d2f4a9bb671fbf872a4 100644 (file)
@@ -539,7 +539,7 @@ err:
 
 static void cxl_unmap_slice_regs(struct cxl_afu *afu)
 {
-       if (afu->p1n_mmio)
+       if (afu->p2n_mmio)
                iounmap(afu->p2n_mmio);
        if (afu->p1n_mmio)
                iounmap(afu->p1n_mmio);
index b1d1983a84a5d8c665bf0b66880e4f6994645d95..2eba002b580b4c9f2c07de079c7aa060c3b7cb6e 100644 (file)
@@ -112,9 +112,10 @@ static int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn,
        unsigned long addr;
 
        phb = pci_bus_to_host(bus);
-       afu = (struct cxl_afu *)phb->private_data;
        if (phb == NULL)
                return PCIBIOS_DEVICE_NOT_FOUND;
+       afu = (struct cxl_afu *)phb->private_data;
+
        if (cxl_pcie_cfg_record(bus->number, devfn) > afu->crs_num)
                return PCIBIOS_DEVICE_NOT_FOUND;
        if (offset >= (unsigned long)phb->cfg_data)
index 2d3db81be0990a1b88109aa7614f74f201930204..6ded3dc36644a31a0bd4775f36df72f1c00a7e0d 100644 (file)
@@ -438,9 +438,6 @@ static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
 {
        struct at24_data *at24;
 
-       if (unlikely(off >= attr->size))
-               return -EFBIG;
-
        at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
        return at24_write(at24, buf, off, count);
 }
index 357b6ae4d207d785176c22d19a2c572617b8220f..458aa5a09c522816febc6abef20d034a67cfea5d 100644 (file)
@@ -552,22 +552,6 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
        schedule_work(&device->event_work);
 }
 
-void mei_cl_bus_remove_devices(struct mei_device *dev)
-{
-       struct mei_cl *cl, *next;
-
-       mutex_lock(&dev->device_lock);
-       list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
-               if (cl->device)
-                       mei_cl_remove_device(cl->device);
-
-               list_del(&cl->device_link);
-               mei_cl_unlink(cl);
-               kfree(cl);
-       }
-       mutex_unlock(&dev->device_lock);
-}
-
 int __init mei_cl_bus_init(void)
 {
        return bus_register(&mei_cl_bus_type);
index 94514b2c7a50277ba4adf8604ce6084b01309967..00c3865ca3b1d42042d78d5558eac547ea8c03a8 100644 (file)
@@ -333,8 +333,6 @@ void mei_stop(struct mei_device *dev)
 
        mei_nfc_host_exit(dev);
 
-       mei_cl_bus_remove_devices(dev);
-
        mutex_lock(&dev->device_lock);
 
        mei_wd_stop(dev);
index 8eb0a9500a90626b5605025309b1abf53e2ee7cb..e9513d651cd36b611920a2f6410c905b344fbf13 100644 (file)
@@ -682,7 +682,7 @@ int mei_register(struct mei_device *dev, struct device *parent)
        /* Fill in the data structures */
        devno = MKDEV(MAJOR(mei_devt), dev->minor);
        cdev_init(&dev->cdev, &mei_fops);
-       dev->cdev.owner = mei_fops.owner;
+       dev->cdev.owner = parent->driver->owner;
 
        /* Add the device */
        ret = cdev_add(&dev->cdev, devno, 1);
index b983c4ecad3800d34e21a453e034ed15d84574f4..290ef3037437816114e6d373d4889c6ee2855c1b 100644 (file)
@@ -402,11 +402,12 @@ void mei_nfc_host_exit(struct mei_device *dev)
 
        cldev->priv_data = NULL;
 
-       mutex_lock(&dev->device_lock);
        /* Need to remove the device here
         * since mei_nfc_free will unlink the clients
         */
        mei_cl_remove_device(cldev);
+
+       mutex_lock(&dev->device_lock);
        mei_nfc_free(ndev);
        mutex_unlock(&dev->device_lock);
 }
index 41e3bdb100611ab2f20836d0f8d7e3a16d9b068a..6dfdae3452d609fd07c82cce24f933771a093a70 100644 (file)
@@ -357,7 +357,7 @@ static void scif_p2p_freesg(struct scatterlist *sg)
 }
 
 static struct scatterlist *
-scif_p2p_setsg(void __iomem *va, int page_size, int page_cnt)
+scif_p2p_setsg(phys_addr_t pa, int page_size, int page_cnt)
 {
        struct scatterlist *sg;
        struct page *page;
@@ -368,16 +368,11 @@ scif_p2p_setsg(void __iomem *va, int page_size, int page_cnt)
                return NULL;
        sg_init_table(sg, page_cnt);
        for (i = 0; i < page_cnt; i++) {
-               page = vmalloc_to_page((void __force *)va);
-               if (!page)
-                       goto p2p_sg_err;
+               page = pfn_to_page(pa >> PAGE_SHIFT);
                sg_set_page(&sg[i], page, page_size, 0);
-               va += page_size;
+               pa += page_size;
        }
        return sg;
-p2p_sg_err:
-       kfree(sg);
-       return NULL;
 }
 
 /* Init p2p mappings required to access peerdev from scifdev */
@@ -395,14 +390,14 @@ scif_init_p2p_info(struct scif_dev *scifdev, struct scif_dev *peerdev)
        p2p = kzalloc(sizeof(*p2p), GFP_KERNEL);
        if (!p2p)
                return NULL;
-       p2p->ppi_sg[SCIF_PPI_MMIO] = scif_p2p_setsg(psdev->mmio->va,
+       p2p->ppi_sg[SCIF_PPI_MMIO] = scif_p2p_setsg(psdev->mmio->pa,
                                                    PAGE_SIZE, num_mmio_pages);
        if (!p2p->ppi_sg[SCIF_PPI_MMIO])
                goto free_p2p;
        p2p->sg_nentries[SCIF_PPI_MMIO] = num_mmio_pages;
        sg_page_shift = get_order(min(psdev->aper->len, (u64)(1 << 30)));
        num_aper_chunks = num_aper_pages >> (sg_page_shift - PAGE_SHIFT);
-       p2p->ppi_sg[SCIF_PPI_APER] = scif_p2p_setsg(psdev->aper->va,
+       p2p->ppi_sg[SCIF_PPI_APER] = scif_p2p_setsg(psdev->aper->pa,
                                                    1 << sg_page_shift,
                                                    num_aper_chunks);
        p2p->sg_nentries[SCIF_PPI_APER] = num_aper_chunks;
index c9c3d20b784b669bf130cffb716b8525470738fa..a1b820fcb2a6ff60093011d696761ba4ca15e584 100644 (file)
@@ -208,6 +208,8 @@ static ssize_t power_ro_lock_show(struct device *dev,
 
        ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
 
+       mmc_blk_put(md);
+
        return ret;
 }
 
index fd9a58e216a50ffde01e8e9fb7610ef09c417af3..6a0f9c79be2652bdf843c40692e7dd188d76567a 100644 (file)
@@ -779,6 +779,7 @@ config MMC_TOSHIBA_PCI
 
 config MMC_MTK
        tristate "MediaTek SD/MMC Card Interface support"
+       depends on HAS_DMA
        help
          This selects the MediaTek(R) Secure digital and Multimedia card Interface.
          If you have a machine with a integrated SD/MMC card reader, say Y or M here.
index b2b411da297b06e73441f8dd51c8bae0b004bcc0..4d120323689043f21c522b44389757f8391d45fc 100644 (file)
@@ -1062,9 +1062,14 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 
                if (status & (CTO_EN | CCRC_EN))
                        end_cmd = 1;
+               if (host->data || host->response_busy) {
+                       end_trans = !end_cmd;
+                       host->response_busy = 0;
+               }
                if (status & (CTO_EN | DTO_EN))
                        hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
-               else if (status & (CCRC_EN | DCRC_EN))
+               else if (status & (CCRC_EN | DCRC_EN | DEB_EN | CEB_EN |
+                                  BADA_EN))
                        hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
 
                if (status & ACE_EN) {
@@ -1081,10 +1086,6 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
                        }
                        dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
                }
-               if (host->data || host->response_busy) {
-                       end_trans = !end_cmd;
-                       host->response_busy = 0;
-               }
        }
 
        OMAP_HSMMC_WRITE(host->base, STAT, status);
index faf0cb910c968abcce26c431422adff3e438f81d..c6b9f6492e1a2529b7f683686bc4d939229dba63 100644 (file)
@@ -581,13 +581,8 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct pltfm_imx_data *imx_data = pltfm_host->priv;
-       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
-       if (boarddata->f_max && (boarddata->f_max < pltfm_host->clock))
-               return boarddata->f_max;
-       else
-               return pltfm_host->clock;
+       return pltfm_host->clock;
 }
 
 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
@@ -878,34 +873,19 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
                         struct sdhci_host *host,
-                        struct esdhc_platform_data *boarddata)
+                        struct pltfm_imx_data *imx_data)
 {
        struct device_node *np = pdev->dev.of_node;
-
-       if (!np)
-               return -ENODEV;
-
-       if (of_get_property(np, "non-removable", NULL))
-               boarddata->cd_type = ESDHC_CD_PERMANENT;
-
-       if (of_get_property(np, "fsl,cd-controller", NULL))
-               boarddata->cd_type = ESDHC_CD_CONTROLLER;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+       int ret;
 
        if (of_get_property(np, "fsl,wp-controller", NULL))
                boarddata->wp_type = ESDHC_WP_CONTROLLER;
 
-       boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
-       if (gpio_is_valid(boarddata->cd_gpio))
-               boarddata->cd_type = ESDHC_CD_GPIO;
-
        boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
        if (gpio_is_valid(boarddata->wp_gpio))
                boarddata->wp_type = ESDHC_WP_GPIO;
 
-       of_property_read_u32(np, "bus-width", &boarddata->max_bus_width);
-
-       of_property_read_u32(np, "max-frequency", &boarddata->f_max);
-
        if (of_find_property(np, "no-1-8-v", NULL))
                boarddata->support_vsel = false;
        else
@@ -916,29 +896,119 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 
        mmc_of_parse_voltage(np, &host->ocr_mask);
 
+       /* sdr50 and sdr104 needs work on 1.8v signal voltage */
+       if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
+           !IS_ERR(imx_data->pins_default)) {
+               imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
+                                               ESDHC_PINCTRL_STATE_100MHZ);
+               imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
+                                               ESDHC_PINCTRL_STATE_200MHZ);
+               if (IS_ERR(imx_data->pins_100mhz) ||
+                               IS_ERR(imx_data->pins_200mhz)) {
+                       dev_warn(mmc_dev(host->mmc),
+                               "could not get ultra high speed state, work on normal mode\n");
+                       /*
+                        * fall back to not support uhs by specify no 1.8v quirk
+                        */
+                       host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+               }
+       } else {
+               host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+       }
+
        /* call to generic mmc_of_parse to support additional capabilities */
-       return mmc_of_parse(host->mmc);
+       ret = mmc_of_parse(host->mmc);
+       if (ret)
+               return ret;
+
+       if (!IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
+               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+
+       return 0;
 }
 #else
 static inline int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
                         struct sdhci_host *host,
-                        struct esdhc_platform_data *boarddata)
+                        struct pltfm_imx_data *imx_data)
 {
        return -ENODEV;
 }
 #endif
 
+static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
+                        struct sdhci_host *host,
+                        struct pltfm_imx_data *imx_data)
+{
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+       int err;
+
+       if (!host->mmc->parent->platform_data) {
+               dev_err(mmc_dev(host->mmc), "no board data!\n");
+               return -EINVAL;
+       }
+
+       imx_data->boarddata = *((struct esdhc_platform_data *)
+                               host->mmc->parent->platform_data);
+       /* write_protect */
+       if (boarddata->wp_type == ESDHC_WP_GPIO) {
+               err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
+               if (err) {
+                       dev_err(mmc_dev(host->mmc),
+                               "failed to request write-protect gpio!\n");
+                       return err;
+               }
+               host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+       }
+
+       /* card_detect */
+       switch (boarddata->cd_type) {
+       case ESDHC_CD_GPIO:
+               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
+               if (err) {
+                       dev_err(mmc_dev(host->mmc),
+                               "failed to request card-detect gpio!\n");
+                       return err;
+               }
+               /* fall through */
+
+       case ESDHC_CD_CONTROLLER:
+               /* we have a working card_detect back */
+               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+               break;
+
+       case ESDHC_CD_PERMANENT:
+               host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+               break;
+
+       case ESDHC_CD_NONE:
+               break;
+       }
+
+       switch (boarddata->max_bus_width) {
+       case 8:
+               host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+               break;
+       case 4:
+               host->mmc->caps |= MMC_CAP_4_BIT_DATA;
+               break;
+       case 1:
+       default:
+               host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
+               break;
+       }
+
+       return 0;
+}
+
 static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
                        of_match_device(imx_esdhc_dt_ids, &pdev->dev);
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_host *host;
-       struct esdhc_platform_data *boarddata;
        int err;
        struct pltfm_imx_data *imx_data;
-       bool dt = true;
 
        host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0);
        if (IS_ERR(host))
@@ -1030,84 +1100,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
                host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 
-       boarddata = &imx_data->boarddata;
-       if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) {
-               if (!host->mmc->parent->platform_data) {
-                       dev_err(mmc_dev(host->mmc), "no board data!\n");
-                       err = -EINVAL;
-                       goto disable_clk;
-               }
-               imx_data->boarddata = *((struct esdhc_platform_data *)
-                                       host->mmc->parent->platform_data);
-               dt = false;
-       }
-       /* write_protect */
-       if (boarddata->wp_type == ESDHC_WP_GPIO && !dt) {
-               err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
-               if (err) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to request write-protect gpio!\n");
-                       goto disable_clk;
-               }
-               host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-       }
-
-       /* card_detect */
-       switch (boarddata->cd_type) {
-       case ESDHC_CD_GPIO:
-               if (dt)
-                       break;
-               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
-               if (err) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to request card-detect gpio!\n");
-                       goto disable_clk;
-               }
-               /* fall through */
-
-       case ESDHC_CD_CONTROLLER:
-               /* we have a working card_detect back */
-               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-               break;
-
-       case ESDHC_CD_PERMANENT:
-               host->mmc->caps |= MMC_CAP_NONREMOVABLE;
-               break;
-
-       case ESDHC_CD_NONE:
-               break;
-       }
-
-       switch (boarddata->max_bus_width) {
-       case 8:
-               host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
-               break;
-       case 4:
-               host->mmc->caps |= MMC_CAP_4_BIT_DATA;
-               break;
-       case 1:
-       default:
-               host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
-               break;
-       }
-
-       /* sdr50 and sdr104 needs work on 1.8v signal voltage */
-       if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
-           !IS_ERR(imx_data->pins_default)) {
-               imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
-                                               ESDHC_PINCTRL_STATE_100MHZ);
-               imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
-                                               ESDHC_PINCTRL_STATE_200MHZ);
-               if (IS_ERR(imx_data->pins_100mhz) ||
-                               IS_ERR(imx_data->pins_200mhz)) {
-                       dev_warn(mmc_dev(host->mmc),
-                               "could not get ultra high speed state, work on normal mode\n");
-                       /* fall back to not support uhs by specify no 1.8v quirk */
-                       host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
-               }
-       } else {
-               host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
-       }
+       if (of_id)
+               err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
+       else
+               err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
+       if (err)
+               goto disable_clk;
 
        err = sdhci_add_host(host);
        if (err)
index 3497cfaf683c539edbd062199e03f5692e43bb26..a870c42731d7a4eea86b39e9e965d94a0603631d 100644 (file)
@@ -45,6 +45,6 @@
 #define ESDHC_DMA_SYSCTL       0x40c
 #define ESDHC_DMA_SNOOP                0x00000040
 
-#define ESDHC_HOST_CONTROL_RES 0x05
+#define ESDHC_HOST_CONTROL_RES 0x01
 
 #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
index 9cd5fc62f130871aaa6390ac8e25b0f0f2fedf03..946d37f94a31b29e8739304ec71cf7b1468eead6 100644 (file)
@@ -411,6 +411,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                        goto err_of_parse;
                sdhci_get_of_property(pdev);
                pdata = pxav3_get_mmc_pdata(dev);
+               pdev->dev.platform_data = pdata;
        } else if (pdata) {
                /* on-chip device */
                if (pdata->flags & PXA_FLAG_CARD_PERMANENT)
index df088343d60f32413a3694813ad97f9abb57b7ae..255a896769b8691ee9178fb5502e3844ccd1555f 100644 (file)
@@ -4,7 +4,7 @@
  * Support of SDHCI platform devices for spear soc family
  *
  * Copyright (C) 2010 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * Inspired by sdhci-pltfm.c
  *
@@ -211,5 +211,5 @@ static struct platform_driver sdhci_driver = {
 module_platform_driver(sdhci_driver);
 
 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_LICENSE("GPL v2");
index bc1445238fb3053b8d2a03a7bb35a25ddfff4b61..1dbe932320309fc87f75a40cc2552ba5a784d5bd 100644 (file)
@@ -2866,6 +2866,7 @@ int sdhci_add_host(struct sdhci_host *host)
        u32 max_current_caps;
        unsigned int ocr_avail;
        unsigned int override_timeout_clk;
+       u32 max_clk;
        int ret;
 
        WARN_ON(host == NULL);
@@ -2978,8 +2979,11 @@ int sdhci_add_host(struct sdhci_host *host)
                                                      GFP_KERNEL);
                host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
                if (!host->adma_table || !host->align_buffer) {
-                       dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
-                                         host->adma_table, host->adma_addr);
+                       if (host->adma_table)
+                               dma_free_coherent(mmc_dev(mmc),
+                                                 host->adma_table_sz,
+                                                 host->adma_table,
+                                                 host->adma_addr);
                        kfree(host->align_buffer);
                        pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
                                mmc_hostname(mmc));
@@ -3047,18 +3051,22 @@ int sdhci_add_host(struct sdhci_host *host)
         * Set host parameters.
         */
        mmc->ops = &sdhci_ops;
-       mmc->f_max = host->max_clk;
+       max_clk = host->max_clk;
+
        if (host->ops->get_min_clock)
                mmc->f_min = host->ops->get_min_clock(host);
        else if (host->version >= SDHCI_SPEC_300) {
                if (host->clk_mul) {
                        mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
-                       mmc->f_max = host->max_clk * host->clk_mul;
+                       max_clk = host->max_clk * host->clk_mul;
                } else
                        mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
+       if (!mmc->f_max || (mmc->f_max && (mmc->f_max > max_clk)))
+               mmc->f_max = max_clk;
+
        if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
                host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>
                                        SDHCI_TIMEOUT_CLK_SHIFT;
index 19eb990d398c03affd47a3a50e01ad0571427aa8..a98dd4f1b0e33126ca04d1a7cecb8ad1e41d8d72 100644 (file)
@@ -625,6 +625,23 @@ static void bond_set_dev_addr(struct net_device *bond_dev,
        call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
 }
 
+static struct slave *bond_get_old_active(struct bonding *bond,
+                                        struct slave *new_active)
+{
+       struct slave *slave;
+       struct list_head *iter;
+
+       bond_for_each_slave(bond, slave, iter) {
+               if (slave == new_active)
+                       continue;
+
+               if (ether_addr_equal(bond->dev->dev_addr, slave->dev->dev_addr))
+                       return slave;
+       }
+
+       return NULL;
+}
+
 /* bond_do_fail_over_mac
  *
  * Perform special MAC address swapping for fail_over_mac settings
@@ -652,6 +669,9 @@ static void bond_do_fail_over_mac(struct bonding *bond,
                if (!new_active)
                        return;
 
+               if (!old_active)
+                       old_active = bond_get_old_active(bond, new_active);
+
                if (old_active) {
                        ether_addr_copy(tmp_mac, new_active->dev->dev_addr);
                        ether_addr_copy(saddr.sa_data,
@@ -689,40 +709,57 @@ out:
 
 }
 
-static bool bond_should_change_active(struct bonding *bond)
+static struct slave *bond_choose_primary_or_current(struct bonding *bond)
 {
        struct slave *prim = rtnl_dereference(bond->primary_slave);
        struct slave *curr = rtnl_dereference(bond->curr_active_slave);
 
-       if (!prim || !curr || curr->link != BOND_LINK_UP)
-               return true;
+       if (!prim || prim->link != BOND_LINK_UP) {
+               if (!curr || curr->link != BOND_LINK_UP)
+                       return NULL;
+               return curr;
+       }
+
        if (bond->force_primary) {
                bond->force_primary = false;
-               return true;
+               return prim;
+       }
+
+       if (!curr || curr->link != BOND_LINK_UP)
+               return prim;
+
+       /* At this point, prim and curr are both up */
+       switch (bond->params.primary_reselect) {
+       case BOND_PRI_RESELECT_ALWAYS:
+               return prim;
+       case BOND_PRI_RESELECT_BETTER:
+               if (prim->speed < curr->speed)
+                       return curr;
+               if (prim->speed == curr->speed && prim->duplex <= curr->duplex)
+                       return curr;
+               return prim;
+       case BOND_PRI_RESELECT_FAILURE:
+               return curr;
+       default:
+               netdev_err(bond->dev, "impossible primary_reselect %d\n",
+                          bond->params.primary_reselect);
+               return curr;
        }
-       if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER &&
-           (prim->speed < curr->speed ||
-            (prim->speed == curr->speed && prim->duplex <= curr->duplex)))
-               return false;
-       if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE)
-               return false;
-       return true;
 }
 
 /**
- * find_best_interface - select the best available slave to be the active one
+ * bond_find_best_slave - select the best available slave to be the active one
  * @bond: our bonding struct
  */
 static struct slave *bond_find_best_slave(struct bonding *bond)
 {
-       struct slave *slave, *bestslave = NULL, *primary;
+       struct slave *slave, *bestslave = NULL;
        struct list_head *iter;
        int mintime = bond->params.updelay;
 
-       primary = rtnl_dereference(bond->primary_slave);
-       if (primary && primary->link == BOND_LINK_UP &&
-           bond_should_change_active(bond))
-               return primary;
+       slave = bond_choose_primary_or_current(bond);
+       if (slave)
+               return slave;
 
        bond_for_each_slave(bond, slave, iter) {
                if (slave->link == BOND_LINK_UP)
@@ -749,6 +786,7 @@ static bool bond_should_notify_peers(struct bonding *bond)
                   slave ? slave->dev->name : "NULL");
 
        if (!slave || !bond->send_peer_notif ||
+           !netif_carrier_ok(bond->dev) ||
            test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
                return false;
 
@@ -1708,9 +1746,16 @@ err_free:
 
 err_undo_flags:
        /* Enslave of first slave has failed and we need to fix master's mac */
-       if (!bond_has_slaves(bond) &&
-           ether_addr_equal_64bits(bond_dev->dev_addr, slave_dev->dev_addr))
-               eth_hw_addr_random(bond_dev);
+       if (!bond_has_slaves(bond)) {
+               if (ether_addr_equal_64bits(bond_dev->dev_addr,
+                                           slave_dev->dev_addr))
+                       eth_hw_addr_random(bond_dev);
+               if (bond_dev->type != ARPHRD_ETHER) {
+                       ether_setup(bond_dev);
+                       bond_dev->flags |= IFF_MASTER;
+                       bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+               }
+       }
 
        return res;
 }
@@ -1899,6 +1944,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
                netdev_info(bond_dev, "Destroying bond %s\n",
                            bond_dev->name);
+               bond_remove_proc_entry(bond);
                unregister_netdevice(bond_dev);
        }
        return ret;
index f4e40aa4d2a21db2be91eb39f46d1e410ac6c0e0..945c0955a9675198a8b0945ddc49dd6668380838 100644 (file)
@@ -577,10 +577,10 @@ static void at91_rx_overflow_err(struct net_device *dev)
 
        cf->can_id |= CAN_ERR_CRTL;
        cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
-       netif_receive_skb(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 }
 
 /**
@@ -642,10 +642,10 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
        }
 
        at91_read_mb(dev, mb, cf);
-       netif_receive_skb(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        can_led_event(dev, CAN_LED_EVENT_RX);
 }
@@ -802,10 +802,10 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr)
                return 0;
 
        at91_poll_err_frame(dev, cf, reg_sr);
-       netif_receive_skb(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -1067,10 +1067,10 @@ static void at91_irq_err(struct net_device *dev)
                return;
 
        at91_irq_err_state(dev, cf, new_state);
-       netif_rx(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        priv->can.state = new_state;
 }
index 27ad312e7abf34bdf94a86ce66fa5ae900da1aed..57dadd52b428a536d71f2364c006641e5e765083 100644 (file)
@@ -424,10 +424,9 @@ static void bfin_can_rx(struct net_device *dev, u16 isrc)
                cf->data[6 - i] = (6 - i) < cf->can_dlc ? (val >> 8) : 0;
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
@@ -508,10 +507,9 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
 
        priv->can.state = state;
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index 041525d2595ced06ee4363bb09f5fe62dfe5b7ec..5d214d1353320856cf3de91d837b910df3f3de24 100644 (file)
@@ -592,6 +592,7 @@ static int c_can_start(struct net_device *dev)
 {
        struct c_can_priv *priv = netdev_priv(dev);
        int err;
+       struct pinctrl *p;
 
        /* basic c_can configuration */
        err = c_can_chip_config(dev);
@@ -604,8 +605,13 @@ static int c_can_start(struct net_device *dev)
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
-       /* activate pins */
-       pinctrl_pm_select_default_state(dev->dev.parent);
+       /* Attempt to use "active" if available else use "default" */
+       p = pinctrl_get_select(priv->device, "active");
+       if (!IS_ERR(p))
+               pinctrl_put(p);
+       else
+               pinctrl_pm_select_default_state(priv->device);
+
        return 0;
 }
 
index c11d4498403617e4dddcea42d085e08355c9a5d2..70a8cbb29e75844a02bea49a937bf0c05a200910 100644 (file)
@@ -504,10 +504,10 @@ static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1)
                for (i = 0; i < cf->can_dlc; i++)
                        cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]);
        }
-       netif_rx(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static int cc770_err(struct net_device *dev, u8 status)
@@ -584,10 +584,10 @@ static int cc770_err(struct net_device *dev, u8 status)
                }
        }
 
-       netif_rx(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index e9b1810d319f0c22fe7760cde4742a879f7ac190..aede704605c66973c6bc3697a91c90f743990a01 100644 (file)
@@ -440,9 +440,6 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx)
                struct can_frame *cf = (struct can_frame *)skb->data;
                u8 dlc = cf->can_dlc;
 
-               if (!(skb->tstamp.tv64))
-                       __net_timestamp(skb);
-
                netif_rx(priv->echo_skb[idx]);
                priv->echo_skb[idx] = NULL;
 
@@ -578,7 +575,6 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
        if (unlikely(!skb))
                return NULL;
 
-       __net_timestamp(skb);
        skb->protocol = htons(ETH_P_CAN);
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -589,6 +585,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
 
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
+       can_skb_prv(skb)->skbcnt = 0;
 
        *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
        memset(*cf, 0, sizeof(struct can_frame));
@@ -607,7 +604,6 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
        if (unlikely(!skb))
                return NULL;
 
-       __net_timestamp(skb);
        skb->protocol = htons(ETH_P_CANFD);
        skb->pkt_type = PACKET_BROADCAST;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -618,6 +614,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
 
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
+       can_skb_prv(skb)->skbcnt = 0;
 
        *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame));
        memset(*cfd, 0, sizeof(struct canfd_frame));
index 6201c5a1a8845f2e3e68f3921a2fcae8e4469217..b1e8d729851cbb5173c1bbec2b34c4893b2ff595 100644 (file)
@@ -577,10 +577,10 @@ static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
                return 0;
 
        do_bus_err(dev, cf, reg_esr);
-       netif_receive_skb(skb);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -622,10 +622,9 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
        if (unlikely(new_state == CAN_STATE_BUS_OFF))
                can_bus_off(dev);
 
-       netif_receive_skb(skb);
-
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        return 1;
 }
@@ -670,10 +669,10 @@ static int flexcan_read_frame(struct net_device *dev)
        }
 
        flexcan_read_fifo(dev, cf);
-       netif_receive_skb(skb);
 
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
 
        can_led_event(dev, CAN_LED_EVENT_RX);
 
index e3d7e22a4fa080504544a245d9e21adb80aea036..db9538d4b3586e7357ae8d46e4db9f25a27cd469 100644 (file)
@@ -1216,11 +1216,12 @@ static int grcan_receive(struct net_device *dev, int budget)
                                cf->data[i] = (u8)(slot[j] >> shift);
                        }
                }
-               netif_receive_skb(skb);
 
                /* Update statistics and read pointer */
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_receive_skb(skb);
+
                rd = grcan_ring_add(rd, GRCAN_MSG_SIZE, dma->rx.size);
        }
 
index 7deb80dcbe8c09b669f15e3f5dfb3af3fc72598e..7bd54191f962a4ad3079eabdcefb0d001a14bf0b 100644 (file)
@@ -508,7 +508,8 @@ static int rcar_can_open(struct net_device *ndev)
 
        err = clk_prepare_enable(priv->clk);
        if (err) {
-               netdev_err(ndev, "failed to enable periperal clock, error %d\n",
+               netdev_err(ndev,
+                          "failed to enable peripheral clock, error %d\n",
                           err);
                goto out;
        }
@@ -526,7 +527,8 @@ static int rcar_can_open(struct net_device *ndev)
        napi_enable(&priv->napi);
        err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
        if (err) {
-               netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq);
+               netdev_err(ndev, "request_irq(%d) failed, error %d\n",
+                          ndev->irq, err);
                goto out_close;
        }
        can_led_event(ndev, CAN_LED_EVENT_OPEN);
@@ -758,8 +760,9 @@ static int rcar_can_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (!irq) {
+       if (irq < 0) {
                dev_err(&pdev->dev, "No IRQ resource\n");
+               err = irq;
                goto fail;
        }
 
@@ -782,7 +785,8 @@ static int rcar_can_probe(struct platform_device *pdev)
        priv->clk = devm_clk_get(&pdev->dev, "clkp1");
        if (IS_ERR(priv->clk)) {
                err = PTR_ERR(priv->clk);
-               dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err);
+               dev_err(&pdev->dev, "cannot get peripheral clock, error %d\n",
+                       err);
                goto fail_clk;
        }
 
@@ -794,7 +798,7 @@ static int rcar_can_probe(struct platform_device *pdev)
        priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]);
        if (IS_ERR(priv->can_clk)) {
                err = PTR_ERR(priv->can_clk);
-               dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err);
+               dev_err(&pdev->dev, "cannot get CAN clock, error %d\n", err);
                goto fail_clk;
        }
 
@@ -823,7 +827,7 @@ static int rcar_can_probe(struct platform_device *pdev)
 
        devm_can_led_init(ndev);
 
-       dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
+       dev_info(&pdev->dev, "device registered (regs @ %p, IRQ%d)\n",
                 priv->regs, ndev->irq);
 
        return 0;
index 32bd7f451aa42b53f0a479af667861db6693d619..7b92e911a6168badb3e30f8fc55b2e6fdd0f61dc 100644 (file)
@@ -377,10 +377,9 @@ static void sja1000_rx(struct net_device *dev)
        /* release receive buffer */
        sja1000_write_cmdreg(priv, CMD_RRB);
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        can_led_event(dev, CAN_LED_EVENT_RX);
 }
@@ -484,10 +483,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                        can_bus_off(dev);
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index f64f5290d6f8f41bd8a4ade0cf81be2811d98911..9a3f15cb7ef4883abebe6bac8ffc5909077d475f 100644 (file)
@@ -207,7 +207,6 @@ static void slc_bump(struct slcan *sl)
        if (!skb)
                return;
 
-       __net_timestamp(skb);
        skb->dev = sl->dev;
        skb->protocol = htons(ETH_P_CAN);
        skb->pkt_type = PACKET_BROADCAST;
@@ -215,13 +214,14 @@ static void slc_bump(struct slcan *sl)
 
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = sl->dev->ifindex;
+       can_skb_prv(skb)->skbcnt = 0;
 
        memcpy(skb_put(skb, sizeof(struct can_frame)),
               &cf, sizeof(struct can_frame));
-       netif_rx_ni(skb);
 
        sl->dev->stats.rx_packets++;
        sl->dev->stats.rx_bytes += cf.can_dlc;
+       netif_rx_ni(skb);
 }
 
 /* parse tty input stream */
index c1a95a34d62ea682d8a2582ddc068ca52c7e592d..b7e83c2120235e133141422ebe037a3bf43e7a15 100644 (file)
@@ -1086,8 +1086,8 @@ static int mcp251x_can_probe(struct spi_device *spi)
        if (ret)
                goto out_clk;
 
-       priv->power = devm_regulator_get(&spi->dev, "vdd");
-       priv->transceiver = devm_regulator_get(&spi->dev, "xceiver");
+       priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
+       priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver");
        if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
            (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
                ret = -EPROBE_DEFER;
@@ -1222,17 +1222,16 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
        struct spi_device *spi = to_spi_device(dev);
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
 
-       if (priv->after_suspend & AFTER_SUSPEND_POWER) {
+       if (priv->after_suspend & AFTER_SUSPEND_POWER)
                mcp251x_power_enable(priv->power, 1);
+
+       if (priv->after_suspend & AFTER_SUSPEND_UP) {
+               mcp251x_power_enable(priv->transceiver, 1);
                queue_work(priv->wq, &priv->restart_work);
        } else {
-               if (priv->after_suspend & AFTER_SUSPEND_UP) {
-                       mcp251x_power_enable(priv->transceiver, 1);
-                       queue_work(priv->wq, &priv->restart_work);
-               } else {
-                       priv->after_suspend = 0;
-               }
+               priv->after_suspend = 0;
        }
+
        priv->force_quit = 0;
        enable_irq(spi->irq);
        return 0;
index e95a9e1a889f19c4673d9735e5e932eb83340767..cf345cbfe8198ef23ee328fc2eb67f5841751ee1 100644 (file)
@@ -747,9 +747,9 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
                }
        }
 
-       netif_rx(skb);
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index 866bac0ae7e966855d1085f5a8735988832a1bb7..2d390384ef3bb3d3845fcf6102bef70715f1dd21 100644 (file)
@@ -324,10 +324,9 @@ static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg)
                        cf->data[i] = msg->msg.can_msg.msg[i];
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
@@ -400,10 +399,9 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
                stats->rx_errors++;
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 /*
index 411c1af92c62c1c93985e4adf7232d1b6b78d8bc..0e5a4493ba4fee6d3c4fb5626a676f18802a6ef3 100644 (file)
@@ -301,13 +301,12 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
                        cf->data[7] = rxerr;
                }
 
-               netif_rx(skb);
-
                priv->bec.txerr = txerr;
                priv->bec.rxerr = rxerr;
 
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
        }
 }
 
@@ -347,10 +346,9 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
                                cf->data[i] = msg->msg.rx.data[i];
                }
 
-               netif_rx(skb);
-
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
        }
 
        return;
index 72427f21edffaa9fed0874085e277aa4c83783b7..6b94007ae05221c94d3dedce77a412e732834337 100644 (file)
@@ -526,9 +526,9 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
                hwts->hwtstamp = timeval_to_ktime(tv);
        }
 
-       netif_rx(skb);
        mc->netdev->stats.rx_packets++;
        mc->netdev->stats.rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
@@ -659,12 +659,11 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
        hwts = skb_hwtstamps(skb);
        hwts->hwtstamp = timeval_to_ktime(tv);
 
-       /* push the skb */
-       netif_rx(skb);
-
        /* update statistics */
        mc->netdev->stats.rx_packets++;
        mc->netdev->stats.rx_bytes += cf->can_dlc;
+       /* push the skb */
+       netif_rx(skb);
 
        return 0;
 
index dec51717635e900aafc91b771e5bfa0a2b594fae..7d61b3279798b936f4a3238afb57c73437ba22f2 100644 (file)
@@ -553,9 +553,9 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
        hwts = skb_hwtstamps(skb);
        hwts->hwtstamp = timeval_to_ktime(tv);
 
-       netif_rx(skb);
        netdev->stats.rx_packets++;
        netdev->stats.rx_bytes += can_frame->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
@@ -670,9 +670,9 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
        peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv);
        hwts = skb_hwtstamps(skb);
        hwts->hwtstamp = timeval_to_ktime(tv);
-       netif_rx(skb);
        netdev->stats.rx_packets++;
        netdev->stats.rx_bytes += can_frame->can_dlc;
+       netif_rx(skb);
 
        return 0;
 }
index dd52c7a4c80d9f26faa74ece8d109ee21045ba47..de95b1ccba3e3b6d4d00e313acb280cd178a000d 100644 (file)
@@ -461,10 +461,9 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
        priv->bec.txerr = txerr;
        priv->bec.rxerr = rxerr;
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 /* Read data and status frames */
@@ -494,10 +493,9 @@ static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
                else
                        memcpy(cf->data, msg->data, cf->can_dlc);
 
-               netif_rx(skb);
-
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
 
                can_led_event(priv->netdev, CAN_LED_EVENT_RX);
        } else {
index 0ce868de855dfeb28533def7b47142d671836e9b..674f367087c54ac168d2c0283b1361a1c98d3696 100644 (file)
@@ -78,9 +78,6 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
        skb->dev       = dev;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-       if (!(skb->tstamp.tv64))
-               __net_timestamp(skb);
-
        netif_rx_ni(skb);
 }
 
index 972982f8bea7af16f253b58d3540cc0b9aa6682b..079897b3a9554b55918c97a94f5ba718c314da38 100644 (file)
@@ -696,9 +696,20 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
        }
 
        /* Include the pseudo-PHY address and the broadcast PHY address to
-        * divert reads towards our workaround
+        * divert reads towards our workaround. This is only required for
+        * 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such
+        * that we can use the regular SWITCH_MDIO master controller instead.
+        *
+        * By default, DSA initializes ds->phys_mii_mask to ds->phys_port_mask
+        * to have a 1:1 mapping between Port address and PHY address in order
+        * to utilize the slave_mii_bus instance to read from Port PHYs. This is
+        * not what we want here, so we initialize phys_mii_mask 0 to always
+        * utilize the "master" MDIO bus backed by the "mdio-unimac" driver.
         */
-       ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
+       if (of_machine_is_compatible("brcm,bcm7445d0"))
+               ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
+       else
+               ds->phys_mii_mask = 0;
 
        rev = reg_readl(priv, REG_SWITCH_REVISION);
        priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
index fd8547c2b79d46786b10807a0c62f338b6a60e27..561342466076c57888bcd92b4f463756f4d10a49 100644 (file)
@@ -1163,7 +1163,7 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask)
 
        newfid = __ffs(ps->fid_mask);
        ps->fid[port] = newfid;
-       ps->fid_mask &= (1 << newfid);
+       ps->fid_mask &= ~(1 << newfid);
        ps->bridge_mask[fid] &= ~(1 << port);
        ps->bridge_mask[newfid] = 1 << port;
 
index 41095ebad97fe15e399d00c293882d542c844b25..753887d02b46abc66663a24a2ea3e4e396d6b881 100644 (file)
@@ -1763,16 +1763,9 @@ vortex_open(struct net_device *dev)
                        vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
                }
                if (i != RX_RING_SIZE) {
-                       int j;
                        pr_emerg("%s: no memory for rx ring\n", dev->name);
-                       for (j = 0; j < i; j++) {
-                               if (vp->rx_skbuff[j]) {
-                                       dev_kfree_skb(vp->rx_skbuff[j]);
-                                       vp->rx_skbuff[j] = NULL;
-                               }
-                       }
                        retval = -ENOMEM;
-                       goto err_free_irq;
+                       goto err_free_skb;
                }
                /* Wrap the ring. */
                vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
@@ -1782,7 +1775,13 @@ vortex_open(struct net_device *dev)
        if (!retval)
                goto out;
 
-err_free_irq:
+err_free_skb:
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               if (vp->rx_skbuff[i]) {
+                       dev_kfree_skb(vp->rx_skbuff[i]);
+                       vp->rx_skbuff[i] = NULL;
+               }
+       }
        free_irq(dev->irq, dev);
 err:
        if (vortex_debug > 1)
@@ -2382,6 +2381,7 @@ boomerang_interrupt(int irq, void *dev_id)
        void __iomem *ioaddr;
        int status;
        int work_done = max_interrupt_work;
+       int handled = 0;
 
        ioaddr = vp->ioaddr;
 
@@ -2400,6 +2400,7 @@ boomerang_interrupt(int irq, void *dev_id)
 
        if ((status & IntLatch) == 0)
                goto handler_exit;              /* No interrupt: shared IRQs can cause this */
+       handled = 1;
 
        if (status == 0xffff) {         /* h/w no longer present (hotplug)? */
                if (vortex_debug > 1)
@@ -2501,7 +2502,7 @@ boomerang_interrupt(int irq, void *dev_id)
 handler_exit:
        vp->handling_irq = 0;
        spin_unlock(&vp->lock);
-       return IRQ_HANDLED;
+       return IRQ_RETVAL(handled);
 }
 
 static int vortex_rx(struct net_device *dev)
index 661cdaa7ea96c26ebc6142c955f12dd19296e49f..b3bc87fe3764e397e4a9ce19518866cb97530771 100644 (file)
@@ -303,7 +303,8 @@ static void xgbe_set_buffer_data(struct xgbe_buffer_data *bd,
        get_page(pa->pages);
        bd->pa = *pa;
 
-       bd->dma = pa->pages_dma + pa->pages_offset;
+       bd->dma_base = pa->pages_dma;
+       bd->dma_off = pa->pages_offset;
        bd->dma_len = len;
 
        pa->pages_offset += len;
index 506e832c9e9a80f8e6da438ac4e2cb42a49435a7..a4473d8ff4fa0e1ec7bbdb511f9edd51f1871d71 100644 (file)
@@ -1110,6 +1110,7 @@ static void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata,
        unsigned int rx_usecs = pdata->rx_usecs;
        unsigned int rx_frames = pdata->rx_frames;
        unsigned int inte;
+       dma_addr_t hdr_dma, buf_dma;
 
        if (!rx_usecs && !rx_frames) {
                /* No coalescing, interrupt for every descriptor */
@@ -1129,10 +1130,12 @@ static void xgbe_rx_desc_reset(struct xgbe_prv_data *pdata,
         *   Set buffer 2 (hi) address to buffer dma address (hi) and
         *     set control bits OWN and INTE
         */
-       rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->rx.hdr.dma));
-       rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->rx.hdr.dma));
-       rdesc->desc2 = cpu_to_le32(lower_32_bits(rdata->rx.buf.dma));
-       rdesc->desc3 = cpu_to_le32(upper_32_bits(rdata->rx.buf.dma));
+       hdr_dma = rdata->rx.hdr.dma_base + rdata->rx.hdr.dma_off;
+       buf_dma = rdata->rx.buf.dma_base + rdata->rx.buf.dma_off;
+       rdesc->desc0 = cpu_to_le32(lower_32_bits(hdr_dma));
+       rdesc->desc1 = cpu_to_le32(upper_32_bits(hdr_dma));
+       rdesc->desc2 = cpu_to_le32(lower_32_bits(buf_dma));
+       rdesc->desc3 = cpu_to_le32(upper_32_bits(buf_dma));
 
        XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, inte);
 
index 1e9c28d19ef88ccd4e0c8b45bf7ee9351c03935c..aae9d5ecd1822b16a2812de3bee503f59113adaa 100644 (file)
@@ -1765,8 +1765,9 @@ static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata,
        /* Start with the header buffer which may contain just the header
         * or the header plus data
         */
-       dma_sync_single_for_cpu(pdata->dev, rdata->rx.hdr.dma,
-                               rdata->rx.hdr.dma_len, DMA_FROM_DEVICE);
+       dma_sync_single_range_for_cpu(pdata->dev, rdata->rx.hdr.dma_base,
+                                     rdata->rx.hdr.dma_off,
+                                     rdata->rx.hdr.dma_len, DMA_FROM_DEVICE);
 
        packet = page_address(rdata->rx.hdr.pa.pages) +
                 rdata->rx.hdr.pa.pages_offset;
@@ -1778,8 +1779,11 @@ static struct sk_buff *xgbe_create_skb(struct xgbe_prv_data *pdata,
        len -= copy_len;
        if (len) {
                /* Add the remaining data as a frag */
-               dma_sync_single_for_cpu(pdata->dev, rdata->rx.buf.dma,
-                                       rdata->rx.buf.dma_len, DMA_FROM_DEVICE);
+               dma_sync_single_range_for_cpu(pdata->dev,
+                                             rdata->rx.buf.dma_base,
+                                             rdata->rx.buf.dma_off,
+                                             rdata->rx.buf.dma_len,
+                                             DMA_FROM_DEVICE);
 
                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
                                rdata->rx.buf.pa.pages,
@@ -1945,8 +1949,9 @@ read_again:
                                if (!skb)
                                        error = 1;
                        } else if (rdesc_len) {
-                               dma_sync_single_for_cpu(pdata->dev,
-                                                       rdata->rx.buf.dma,
+                               dma_sync_single_range_for_cpu(pdata->dev,
+                                                       rdata->rx.buf.dma_base,
+                                                       rdata->rx.buf.dma_off,
                                                        rdata->rx.buf.dma_len,
                                                        DMA_FROM_DEVICE);
 
index 63d72a140053956c35b82b2982497db2fbf1e440..717ce21b60776b1e5162833a83aefa1fa95081b1 100644 (file)
@@ -337,7 +337,8 @@ struct xgbe_buffer_data {
        struct xgbe_page_alloc pa;
        struct xgbe_page_alloc pa_unmap;
 
-       dma_addr_t dma;
+       dma_addr_t dma_base;
+       unsigned long dma_off;
        unsigned int dma_len;
 };
 
index 909ad7a0d48088fcaa8295dfdd3b3617becf8d12..4566cdf0bc398e977b310729a3ab129a190bc9b1 100644 (file)
@@ -1793,7 +1793,7 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        macaddr = of_get_mac_address(dn);
        if (!macaddr || !is_valid_ether_addr(macaddr)) {
                dev_warn(&pdev->dev, "using random Ethernet MAC\n");
-               random_ether_addr(dev->dev_addr);
+               eth_hw_addr_random(dev);
        } else {
                ether_addr_copy(dev->dev_addr, macaddr);
        }
index a90d7364334f9dfa3687dc813e068508a342861c..f7fbdc9d132511b72df0db2ce0b92e4df0774c44 100644 (file)
@@ -262,9 +262,9 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
        if (likely(skb)) {
                (*pkts_compl)++;
                (*bytes_compl) += skb->len;
+               dev_kfree_skb_any(skb);
        }
 
-       dev_kfree_skb_any(skb);
        tx_buf->first_bd = 0;
        tx_buf->skb = NULL;
 
index 76b9052a961c517978494199d74398264583508c..5907c821d131eed6fa5b6b0aa7a93dc41cca0d66 100644 (file)
@@ -1718,6 +1718,22 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
                offset += sizeof(u32);
                data_buf += sizeof(u32);
                written_so_far += sizeof(u32);
+
+               /* At end of each 4Kb page, release nvram lock to allow MFW
+                * chance to take it for its own use.
+                */
+               if ((cmd_flags & MCPR_NVM_COMMAND_LAST) &&
+                   (written_so_far < buf_size)) {
+                       DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+                          "Releasing NVM lock after offset 0x%x\n",
+                          (u32)(offset - sizeof(u32)));
+                       bnx2x_release_nvram_lock(bp);
+                       usleep_range(1000, 2000);
+                       rc = bnx2x_acquire_nvram_lock(bp);
+                       if (rc)
+                               return rc;
+               }
+
                cmd_flags = 0;
        }
 
index b43b2cb9b830bfc64c1586fb4058f06596671f6e..64c1e9db6b0b5420687c1c083cc20b8adb7de5bd 100644 (file)
@@ -1230,7 +1230,6 @@ static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev,
                new_skb = skb_realloc_headroom(skb, sizeof(*status));
                dev_kfree_skb(skb);
                if (!new_skb) {
-                       dev->stats.tx_errors++;
                        dev->stats.tx_dropped++;
                        return NULL;
                }
@@ -1465,7 +1464,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 
                if (unlikely(!skb)) {
                        dev->stats.rx_dropped++;
-                       dev->stats.rx_errors++;
                        goto next;
                }
 
@@ -1493,7 +1491,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
                if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
                        netif_err(priv, rx_status, dev,
                                  "dropping fragmented packet!\n");
-                       dev->stats.rx_dropped++;
                        dev->stats.rx_errors++;
                        dev_kfree_skb_any(skb);
                        goto next;
@@ -1515,7 +1512,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
                                dev->stats.rx_frame_errors++;
                        if (dma_flag & DMA_RX_LG)
                                dev->stats.rx_length_errors++;
-                       dev->stats.rx_dropped++;
                        dev->stats.rx_errors++;
                        dev_kfree_skb_any(skb);
                        goto next;
index ac27e24264a5666e4e7418ee6fd252868b617b09..f557a2aaec231ff0669db71a1b6eee07cca7d90f 100644 (file)
@@ -1508,16 +1508,7 @@ static void sbmac_channel_start(struct sbmac_softc *s)
        __raw_writeq(reg, port);
        port = s->sbm_base + R_MAC_ETHERNET_ADDR;
 
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
-       /*
-        * Pass1 SOCs do not receive packets addressed to the
-        * destination address in the R_MAC_ETHERNET_ADDR register.
-        * Set the value to zero.
-        */
-       __raw_writeq(0, port);
-#else
        __raw_writeq(reg, port);
-#endif
 
        /*
         * Set the receive filter for no packets, and write values
index 0612b19f6313bd3e6ffa205be2b543585262e31e..506047c386071db9472d60218faa004fe94849a8 100644 (file)
@@ -676,6 +676,7 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                        if (!next_cmpl->valid)
                                break;
                }
+               packets++;
 
                /* TODO: BNA_CQ_EF_LOCAL ? */
                if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR |
@@ -692,7 +693,6 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                else
                        bnad_cq_setup_skb_frags(rcb, skb, sop_ci, nvecs, len);
 
-               packets++;
                rcb->rxq->rx_packets++;
                rcb->rxq->rx_bytes += totlen;
                ccb->bytes_per_intr += totlen;
index caeb39561567237261ac0d50befebad666cfbeb3..bf9eb2ecf96003e066418d93c7d22aae89c76a31 100644 (file)
@@ -104,6 +104,57 @@ static void *macb_rx_buffer(struct macb *bp, unsigned int index)
        return bp->rx_buffers + bp->rx_buffer_size * macb_rx_ring_wrap(index);
 }
 
+/* I/O accessors */
+static u32 hw_readl_native(struct macb *bp, int offset)
+{
+       return __raw_readl(bp->regs + offset);
+}
+
+static void hw_writel_native(struct macb *bp, int offset, u32 value)
+{
+       __raw_writel(value, bp->regs + offset);
+}
+
+static u32 hw_readl(struct macb *bp, int offset)
+{
+       return readl_relaxed(bp->regs + offset);
+}
+
+static void hw_writel(struct macb *bp, int offset, u32 value)
+{
+       writel_relaxed(value, bp->regs + offset);
+}
+
+/*
+ * Find the CPU endianness by using the loopback bit of NCR register. When the
+ * CPU is in big endian we need to program swaped mode for management
+ * descriptor access.
+ */
+static bool hw_is_native_io(void __iomem *addr)
+{
+       u32 value = MACB_BIT(LLB);
+
+       __raw_writel(value, addr + MACB_NCR);
+       value = __raw_readl(addr + MACB_NCR);
+
+       /* Write 0 back to disable everything */
+       __raw_writel(0, addr + MACB_NCR);
+
+       return value == MACB_BIT(LLB);
+}
+
+static bool hw_is_gem(void __iomem *addr, bool native_io)
+{
+       u32 id;
+
+       if (native_io)
+               id = __raw_readl(addr + MACB_MID);
+       else
+               id = readl_relaxed(addr + MACB_MID);
+
+       return MACB_BFEXT(IDNUM, id) >= 0x2;
+}
+
 static void macb_set_hwaddr(struct macb *bp)
 {
        u32 bottom;
@@ -160,7 +211,7 @@ static void macb_get_hwaddr(struct macb *bp)
                }
        }
 
-       netdev_info(bp->dev, "invalid hw address, using random\n");
+       dev_info(&bp->pdev->dev, "invalid hw address, using random\n");
        eth_hw_addr_random(bp->dev);
 }
 
@@ -252,7 +303,6 @@ static void macb_handle_link_change(struct net_device *dev)
        struct macb *bp = netdev_priv(dev);
        struct phy_device *phydev = bp->phy_dev;
        unsigned long flags;
-
        int status_change = 0;
 
        spin_lock_irqsave(&bp->lock, flags);
@@ -449,14 +499,14 @@ err_out:
 
 static void macb_update_stats(struct macb *bp)
 {
-       u32 __iomem *reg = bp->regs + MACB_PFR;
        u32 *p = &bp->hw_stats.macb.rx_pause_frames;
        u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1;
+       int offset = MACB_PFR;
 
        WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4);
 
-       for(; p < end; p++, reg++)
-               *p += readl_relaxed(reg);
+       for(; p < end; p++, offset += 4)
+               *p += bp->macb_reg_readl(bp, offset);
 }
 
 static int macb_halt_tx(struct macb *bp)
@@ -1107,12 +1157,6 @@ static void macb_poll_controller(struct net_device *dev)
 }
 #endif
 
-static inline unsigned int macb_count_tx_descriptors(struct macb *bp,
-                                                    unsigned int len)
-{
-       return (len + bp->max_tx_length - 1) / bp->max_tx_length;
-}
-
 static unsigned int macb_tx_map(struct macb *bp,
                                struct macb_queue *queue,
                                struct sk_buff *skb)
@@ -1263,11 +1307,11 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
         * socket buffer: skb fragments of jumbo frames may need to be
         * splitted into many buffer descriptors.
         */
-       count = macb_count_tx_descriptors(bp, skb_headlen(skb));
+       count = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length);
        nr_frags = skb_shinfo(skb)->nr_frags;
        for (f = 0; f < nr_frags; f++) {
                frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
-               count += macb_count_tx_descriptors(bp, frag_size);
+               count += DIV_ROUND_UP(frag_size, bp->max_tx_length);
        }
 
        spin_lock_irqsave(&bp->lock, flags);
@@ -1603,7 +1647,6 @@ static u32 macb_dbw(struct macb *bp)
 static void macb_configure_dma(struct macb *bp)
 {
        u32 dmacfg;
-       u32 tmp, ncr;
 
        if (macb_is_gem(bp)) {
                dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
@@ -1613,22 +1656,11 @@ static void macb_configure_dma(struct macb *bp)
                dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
                dmacfg &= ~GEM_BIT(ENDIA_PKT);
 
-               /* Find the CPU endianness by using the loopback bit of net_ctrl
-                * register. save it first. When the CPU is in big endian we
-                * need to program swaped mode for management descriptor access.
-                */
-               ncr = macb_readl(bp, NCR);
-               __raw_writel(MACB_BIT(LLB), bp->regs + MACB_NCR);
-               tmp =  __raw_readl(bp->regs + MACB_NCR);
-
-               if (tmp == MACB_BIT(LLB))
+               if (bp->native_io)
                        dmacfg &= ~GEM_BIT(ENDIA_DESC);
                else
                        dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
 
-               /* Restore net_ctrl */
-               macb_writel(bp, NCR, ncr);
-
                if (bp->dev->features & NETIF_F_HW_CSUM)
                        dmacfg |= GEM_BIT(TXCOEN);
                else
@@ -1897,19 +1929,19 @@ static int macb_change_mtu(struct net_device *dev, int new_mtu)
 
 static void gem_update_stats(struct macb *bp)
 {
-       int i;
+       unsigned int i;
        u32 *p = &bp->hw_stats.gem.tx_octets_31_0;
 
        for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
                u32 offset = gem_statistics[i].offset;
-               u64 val = readl_relaxed(bp->regs + offset);
+               u64 val = bp->macb_reg_readl(bp, offset);
 
                bp->ethtool_stats[i] += val;
                *p += val;
 
                if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
                        /* Add GEM_OCTTXH, GEM_OCTRXH */
-                       val = readl_relaxed(bp->regs + offset + 4);
+                       val = bp->macb_reg_readl(bp, offset + 4);
                        bp->ethtool_stats[i] += ((u64)val) << 32;
                        *(++p) += val;
                }
@@ -1976,7 +2008,7 @@ static int gem_get_sset_count(struct net_device *dev, int sset)
 
 static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p)
 {
-       int i;
+       unsigned int i;
 
        switch (sset) {
        case ETH_SS_STATS:
@@ -2190,7 +2222,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co
        if (dt_conf)
                bp->caps = dt_conf->caps;
 
-       if (macb_is_gem_hw(bp->regs)) {
+       if (hw_is_gem(bp->regs, bp->native_io)) {
                bp->caps |= MACB_CAPS_MACB_IS_GEM;
 
                dcfg = gem_readl(bp, DCFG1);
@@ -2201,10 +2233,11 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co
                        bp->caps |= MACB_CAPS_FIFO_MODE;
        }
 
-       netdev_dbg(bp->dev, "Cadence caps 0x%08x\n", bp->caps);
+       dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps);
 }
 
 static void macb_probe_queues(void __iomem *mem,
+                             bool native_io,
                              unsigned int *queue_mask,
                              unsigned int *num_queues)
 {
@@ -2219,7 +2252,7 @@ static void macb_probe_queues(void __iomem *mem,
         * we are early in the probe process and don't have the
         * MACB_CAPS_MACB_IS_GEM flag positioned
         */
-       if (!macb_is_gem_hw(mem))
+       if (!hw_is_gem(mem, native_io))
                return;
 
        /* bit 0 is never set but queue 0 always exists */
@@ -2786,6 +2819,7 @@ static int macb_probe(struct platform_device *pdev)
        struct clk *pclk, *hclk, *tx_clk;
        unsigned int queue_mask, num_queues;
        struct macb_platform_data *pdata;
+       bool native_io;
        struct phy_device *phydev;
        struct net_device *dev;
        struct resource *regs;
@@ -2794,6 +2828,11 @@ static int macb_probe(struct platform_device *pdev)
        struct macb *bp;
        int err;
 
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mem = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(mem))
+               return PTR_ERR(mem);
+
        if (np) {
                const struct of_device_id *match;
 
@@ -2809,14 +2848,9 @@ static int macb_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mem = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(mem)) {
-               err = PTR_ERR(mem);
-               goto err_disable_clocks;
-       }
+       native_io = hw_is_native_io(mem);
 
-       macb_probe_queues(mem, &queue_mask, &num_queues);
+       macb_probe_queues(mem, native_io, &queue_mask, &num_queues);
        dev = alloc_etherdev_mq(sizeof(*bp), num_queues);
        if (!dev) {
                err = -ENOMEM;
@@ -2831,6 +2865,14 @@ static int macb_probe(struct platform_device *pdev)
        bp->pdev = pdev;
        bp->dev = dev;
        bp->regs = mem;
+       bp->native_io = native_io;
+       if (native_io) {
+               bp->macb_reg_readl = hw_readl_native;
+               bp->macb_reg_writel = hw_writel_native;
+       } else {
+               bp->macb_reg_readl = hw_readl;
+               bp->macb_reg_writel = hw_writel;
+       }
        bp->num_queues = num_queues;
        bp->queue_mask = queue_mask;
        if (macb_config)
@@ -2838,9 +2880,8 @@ static int macb_probe(struct platform_device *pdev)
        bp->pclk = pclk;
        bp->hclk = hclk;
        bp->tx_clk = tx_clk;
-       if (macb_config->jumbo_max_len) {
+       if (macb_config)
                bp->jumbo_max_len = macb_config->jumbo_max_len;
-       }
 
        spin_lock_init(&bp->lock);
 
index d74655993d4bf19cec68ab227263f5f069467e4c..1895b6b2adddc00188b515004ca5359b860fdc0f 100644 (file)
         | GEM_BF(name, value))
 
 /* Register access macros */
-#define macb_readl(port,reg)                           \
-       readl_relaxed((port)->regs + MACB_##reg)
-#define macb_writel(port,reg,value)                    \
-       writel_relaxed((value), (port)->regs + MACB_##reg)
-#define gem_readl(port, reg)                           \
-       readl_relaxed((port)->regs + GEM_##reg)
-#define gem_writel(port, reg, value)                   \
-       writel_relaxed((value), (port)->regs + GEM_##reg)
-#define queue_readl(queue, reg)                                \
-       readl_relaxed((queue)->bp->regs + (queue)->reg)
-#define queue_writel(queue, reg, value)                        \
-       writel_relaxed((value), (queue)->bp->regs + (queue)->reg)
+#define macb_readl(port, reg)          (port)->macb_reg_readl((port), MACB_##reg)
+#define macb_writel(port, reg, value)  (port)->macb_reg_writel((port), MACB_##reg, (value))
+#define gem_readl(port, reg)           (port)->macb_reg_readl((port), GEM_##reg)
+#define gem_writel(port, reg, value)   (port)->macb_reg_writel((port), GEM_##reg, (value))
+#define queue_readl(queue, reg)                (queue)->bp->macb_reg_readl((queue)->bp, (queue)->reg)
+#define queue_writel(queue, reg, value)        (queue)->bp->macb_reg_writel((queue)->bp, (queue)->reg, (value))
 
 /* Conditional GEM/MACB macros.  These perform the operation to the correct
  * register dependent on whether the device is a GEM or a MACB.  For registers
@@ -785,6 +779,11 @@ struct macb_queue {
 
 struct macb {
        void __iomem            *regs;
+       bool                    native_io;
+
+       /* hardware IO accessors */
+       u32     (*macb_reg_readl)(struct macb *bp, int offset);
+       void    (*macb_reg_writel)(struct macb *bp, int offset, u32 value);
 
        unsigned int            rx_tail;
        unsigned int            rx_prepared_head;
@@ -817,9 +816,9 @@ struct macb {
 
        struct mii_bus          *mii_bus;
        struct phy_device       *phy_dev;
-       unsigned int            link;
-       unsigned int            speed;
-       unsigned int            duplex;
+       int                     link;
+       int                     speed;
+       int                     duplex;
 
        u32                     caps;
        unsigned int            dma_burst_length;
@@ -843,9 +842,4 @@ static inline bool macb_is_gem(struct macb *bp)
        return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
 }
 
-static inline bool macb_is_gem_hw(void __iomem *addr)
-{
-       return !!(MACB_BFEXT(IDNUM, readl_relaxed(addr + MACB_MID)) >= 0x2);
-}
-
 #endif /* _MACB_H */
index c4d6bbe9458dbfe9c726fdff1e9b6c4c64b8a33f..02e23e6f142487ddc8cc2a8d4e2c512cb7e6db62 100644 (file)
@@ -16,7 +16,6 @@ if NET_VENDOR_CAVIUM
 config THUNDER_NIC_PF
        tristate "Thunder Physical function driver"
        depends on 64BIT
-       default ARCH_THUNDER
        select THUNDER_NIC_BGX
        ---help---
          This driver supports Thunder's NIC physical function.
@@ -29,14 +28,12 @@ config THUNDER_NIC_PF
 config THUNDER_NIC_VF
        tristate "Thunder Virtual function driver"
        depends on 64BIT
-       default ARCH_THUNDER
        ---help---
          This driver supports Thunder's NIC virtual function
 
 config THUNDER_NIC_BGX
        tristate "Thunder MAC interface driver (BGX)"
        depends on 64BIT
-       default ARCH_THUNDER
        ---help---
          This driver supports programming and controlling of MAC
          interface from NIC physical function driver.
index dda8a02b7322d63197d583ab1c107226ea913051..8aee250904ec83de7b230bf186c3835e0957f46a 100644 (file)
  */
 #define NICPF_CLK_PER_INT_TICK         2
 
+/* Time to wait before we decide that a SQ is stuck.
+ *
+ * Since both pkt rx and tx notifications are done with same CQ,
+ * when packets are being received at very high rate (eg: L2 forwarding)
+ * then freeing transmitted skbs will be delayed and watchdog
+ * will kick in, resetting interface. Hence keeping this value high.
+ */
+#define        NICVF_TX_TIMEOUT                (50 * HZ)
+
 struct nicvf_cq_poll {
        u8      cq_idx;         /* Completion queue index */
        struct  napi_struct napi;
@@ -216,8 +225,9 @@ struct nicvf_drv_stats {
        /* Tx */
        u64 tx_frames_ok;
        u64 tx_drops;
-       u64 tx_busy;
        u64 tx_tso;
+       u64 txq_stop;
+       u64 txq_wake;
 };
 
 struct nicvf {
index 16bd2d772db9f81da0969f7594c4aa3b1761c30f..a4228e66456707d3da44e0cfce653b318b180444 100644 (file)
@@ -66,9 +66,10 @@ static const struct nicvf_stat nicvf_drv_stats[] = {
        NICVF_DRV_STAT(rx_frames_jumbo),
        NICVF_DRV_STAT(rx_drops),
        NICVF_DRV_STAT(tx_frames_ok),
-       NICVF_DRV_STAT(tx_busy),
        NICVF_DRV_STAT(tx_tso),
        NICVF_DRV_STAT(tx_drops),
+       NICVF_DRV_STAT(txq_stop),
+       NICVF_DRV_STAT(txq_wake),
 };
 
 static const struct nicvf_stat nicvf_queue_stats[] = {
@@ -126,6 +127,7 @@ static void nicvf_set_msglevel(struct net_device *netdev, u32 lvl)
 
 static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
 {
+       struct nicvf *nic = netdev_priv(netdev);
        int stats, qidx;
 
        if (sset != ETH_SS_STATS)
@@ -141,7 +143,7 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
                data += ETH_GSTRING_LEN;
        }
 
-       for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
                for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
                        sprintf(data, "rxq%d: %s", qidx,
                                nicvf_queue_stats[stats].name);
@@ -149,7 +151,7 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
                }
        }
 
-       for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
                for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
                        sprintf(data, "txq%d: %s", qidx,
                                nicvf_queue_stats[stats].name);
@@ -170,12 +172,14 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
 
 static int nicvf_get_sset_count(struct net_device *netdev, int sset)
 {
+       struct nicvf *nic = netdev_priv(netdev);
+
        if (sset != ETH_SS_STATS)
                return -EINVAL;
 
        return nicvf_n_hw_stats + nicvf_n_drv_stats +
                (nicvf_n_queue_stats *
-                (MAX_RCV_QUEUES_PER_QS + MAX_SND_QUEUES_PER_QS)) +
+                (nic->qs->rq_cnt + nic->qs->sq_cnt)) +
                BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT;
 }
 
@@ -197,13 +201,13 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev,
                *(data++) = ((u64 *)&nic->drv_stats)
                                [nicvf_drv_stats[stat].index];
 
-       for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
                for (stat = 0; stat < nicvf_n_queue_stats; stat++)
                        *(data++) = ((u64 *)&nic->qs->rq[qidx].stats)
                                        [nicvf_queue_stats[stat].index];
        }
 
-       for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
+       for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
                for (stat = 0; stat < nicvf_n_queue_stats; stat++)
                        *(data++) = ((u64 *)&nic->qs->sq[qidx].stats)
                                        [nicvf_queue_stats[stat].index];
@@ -543,6 +547,7 @@ static int nicvf_set_channels(struct net_device *dev,
 {
        struct nicvf *nic = netdev_priv(dev);
        int err = 0;
+       bool if_up = netif_running(dev);
 
        if (!channel->rx_count || !channel->tx_count)
                return -EINVAL;
@@ -551,6 +556,9 @@ static int nicvf_set_channels(struct net_device *dev,
        if (channel->tx_count > MAX_SND_QUEUES_PER_QS)
                return -EINVAL;
 
+       if (if_up)
+               nicvf_stop(dev);
+
        nic->qs->rq_cnt = channel->rx_count;
        nic->qs->sq_cnt = channel->tx_count;
        nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
@@ -559,11 +567,9 @@ static int nicvf_set_channels(struct net_device *dev,
        if (err)
                return err;
 
-       if (!netif_running(dev))
-               return err;
+       if (if_up)
+               nicvf_open(dev);
 
-       nicvf_stop(dev);
-       nicvf_open(dev);
        netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
                    nic->qs->sq_cnt, nic->qs->rq_cnt);
 
index 8b119a035b7e2f547a9259ce35eb390ce09c4b90..3b90afb8c293254e999f76f3ebbfbd0108dd7022 100644 (file)
@@ -234,7 +234,7 @@ static void  nicvf_handle_mbx_intr(struct nicvf *nic)
                                    nic->duplex == DUPLEX_FULL ?
                                "Full duplex" : "Half duplex");
                        netif_carrier_on(nic->netdev);
-                       netif_tx_wake_all_queues(nic->netdev);
+                       netif_tx_start_all_queues(nic->netdev);
                } else {
                        netdev_info(nic->netdev, "%s: Link is Down\n",
                                    nic->netdev->name);
@@ -425,6 +425,7 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev,
        if (skb) {
                prefetch(skb);
                dev_consume_skb_any(skb);
+               sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL;
        }
 }
 
@@ -476,12 +477,13 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
 static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
                                 struct napi_struct *napi, int budget)
 {
-       int processed_cqe, work_done = 0;
+       int processed_cqe, work_done = 0, tx_done = 0;
        int cqe_count, cqe_head;
        struct nicvf *nic = netdev_priv(netdev);
        struct queue_set *qs = nic->qs;
        struct cmp_queue *cq = &qs->cq[cq_idx];
        struct cqe_rx_t *cq_desc;
+       struct netdev_queue *txq;
 
        spin_lock_bh(&cq->lock);
 loop:
@@ -496,8 +498,8 @@ loop:
        cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_idx) >> 9;
        cqe_head &= 0xFFFF;
 
-       netdev_dbg(nic->netdev, "%s cqe_count %d cqe_head %d\n",
-                  __func__, cqe_count, cqe_head);
+       netdev_dbg(nic->netdev, "%s CQ%d cqe_count %d cqe_head %d\n",
+                  __func__, cq_idx, cqe_count, cqe_head);
        while (processed_cqe < cqe_count) {
                /* Get the CQ descriptor */
                cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
@@ -511,8 +513,8 @@ loop:
                        break;
                }
 
-               netdev_dbg(nic->netdev, "cq_desc->cqe_type %d\n",
-                          cq_desc->cqe_type);
+               netdev_dbg(nic->netdev, "CQ%d cq_desc->cqe_type %d\n",
+                          cq_idx, cq_desc->cqe_type);
                switch (cq_desc->cqe_type) {
                case CQE_TYPE_RX:
                        nicvf_rcv_pkt_handler(netdev, napi, cq,
@@ -522,6 +524,7 @@ loop:
                case CQE_TYPE_SEND:
                        nicvf_snd_pkt_handler(netdev, cq,
                                              (void *)cq_desc, CQE_TYPE_SEND);
+                       tx_done++;
                break;
                case CQE_TYPE_INVALID:
                case CQE_TYPE_RX_SPLIT:
@@ -532,8 +535,9 @@ loop:
                }
                processed_cqe++;
        }
-       netdev_dbg(nic->netdev, "%s processed_cqe %d work_done %d budget %d\n",
-                  __func__, processed_cqe, work_done, budget);
+       netdev_dbg(nic->netdev,
+                  "%s CQ%d processed_cqe %d work_done %d budget %d\n",
+                  __func__, cq_idx, processed_cqe, work_done, budget);
 
        /* Ring doorbell to inform H/W to reuse processed CQEs */
        nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
@@ -543,6 +547,19 @@ loop:
                goto loop;
 
 done:
+       /* Wakeup TXQ if its stopped earlier due to SQ full */
+       if (tx_done) {
+               txq = netdev_get_tx_queue(netdev, cq_idx);
+               if (netif_tx_queue_stopped(txq)) {
+                       netif_tx_start_queue(txq);
+                       nic->drv_stats.txq_wake++;
+                       if (netif_msg_tx_err(nic))
+                               netdev_warn(netdev,
+                                           "%s: Transmit queue wakeup SQ%d\n",
+                                           netdev->name, cq_idx);
+               }
+       }
+
        spin_unlock_bh(&cq->lock);
        return work_done;
 }
@@ -554,15 +571,10 @@ static int nicvf_poll(struct napi_struct *napi, int budget)
        struct net_device *netdev = napi->dev;
        struct nicvf *nic = netdev_priv(netdev);
        struct nicvf_cq_poll *cq;
-       struct netdev_queue *txq;
 
        cq = container_of(napi, struct nicvf_cq_poll, napi);
        work_done = nicvf_cq_intr_handler(netdev, cq->cq_idx, napi, budget);
 
-       txq = netdev_get_tx_queue(netdev, cq->cq_idx);
-       if (netif_tx_queue_stopped(txq))
-               netif_tx_wake_queue(txq);
-
        if (work_done < budget) {
                /* Slow packet rate, exit polling */
                napi_complete(napi);
@@ -833,9 +845,9 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_OK;
        }
 
-       if (!nicvf_sq_append_skb(nic, skb) && !netif_tx_queue_stopped(txq)) {
+       if (!netif_tx_queue_stopped(txq) && !nicvf_sq_append_skb(nic, skb)) {
                netif_tx_stop_queue(txq);
-               nic->drv_stats.tx_busy++;
+               nic->drv_stats.txq_stop++;
                if (netif_msg_tx_err(nic))
                        netdev_warn(netdev,
                                    "%s: Transmit ring full, stopping SQ%d\n",
@@ -859,7 +871,6 @@ int nicvf_stop(struct net_device *netdev)
        nicvf_send_msg_to_pf(nic, &mbx);
 
        netif_carrier_off(netdev);
-       netif_tx_disable(netdev);
 
        /* Disable RBDR & QS error interrupts */
        for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
@@ -894,6 +905,8 @@ int nicvf_stop(struct net_device *netdev)
                kfree(cq_poll);
        }
 
+       netif_tx_disable(netdev);
+
        /* Free resources */
        nicvf_config_data_transfer(nic, false);
 
@@ -988,6 +1001,9 @@ int nicvf_open(struct net_device *netdev)
        for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
                nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx);
 
+       nic->drv_stats.txq_stop = 0;
+       nic->drv_stats.txq_wake = 0;
+
        netif_carrier_on(netdev);
        netif_tx_start_all_queues(netdev);
 
@@ -1278,6 +1294,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netdev->hw_features = netdev->features;
 
        netdev->netdev_ops = &nicvf_netdev_ops;
+       netdev->watchdog_timeo = NICVF_TX_TIMEOUT;
 
        INIT_WORK(&nic->reset_task, nicvf_reset_task);
 
@@ -1318,11 +1335,17 @@ static void nicvf_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
+static void nicvf_shutdown(struct pci_dev *pdev)
+{
+       nicvf_remove(pdev);
+}
+
 static struct pci_driver nicvf_driver = {
        .name = DRV_NAME,
        .id_table = nicvf_id_table,
        .probe = nicvf_probe,
        .remove = nicvf_remove,
+       .shutdown = nicvf_shutdown,
 };
 
 static int __init nicvf_init_module(void)
index d69d228d11a013b4cb709041e49472a9b3b34040..ca4240aa6d1567c044442c239c16f330bdd4f0f4 100644 (file)
@@ -103,9 +103,11 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, gfp_t gfp,
 
        /* Allocate a new page */
        if (!nic->rb_page) {
-               nic->rb_page = alloc_pages(gfp | __GFP_COMP, order);
+               nic->rb_page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
+                                          order);
                if (!nic->rb_page) {
-                       netdev_err(nic->netdev, "Failed to allocate new rcv buffer\n");
+                       netdev_err(nic->netdev,
+                                  "Failed to allocate new rcv buffer\n");
                        return -ENOMEM;
                }
                nic->rb_page_offset = 0;
@@ -382,7 +384,8 @@ static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
                return;
 
        if (sq->tso_hdrs)
-               dma_free_coherent(&nic->pdev->dev, sq->dmem.q_len,
+               dma_free_coherent(&nic->pdev->dev,
+                                 sq->dmem.q_len * TSO_HEADER_SIZE,
                                  sq->tso_hdrs, sq->tso_hdrs_phys);
 
        kfree(sq->skbuff);
@@ -863,10 +866,11 @@ void nicvf_sq_free_used_descs(struct net_device *netdev, struct snd_queue *sq,
                        continue;
                }
                skb = (struct sk_buff *)sq->skbuff[sq->head];
+               if (skb)
+                       dev_kfree_skb_any(skb);
                atomic64_add(1, (atomic64_t *)&netdev->stats.tx_packets);
                atomic64_add(hdr->tot_len,
                             (atomic64_t *)&netdev->stats.tx_bytes);
-               dev_kfree_skb_any(skb);
                nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
        }
 }
@@ -992,7 +996,7 @@ static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
 
        memset(gather, 0, SND_QUEUE_DESC_SIZE);
        gather->subdesc_type = SQ_DESC_TYPE_GATHER;
-       gather->ld_type = NIC_SEND_LD_TYPE_E_LDWB;
+       gather->ld_type = NIC_SEND_LD_TYPE_E_LDD;
        gather->size = size;
        gather->addr = data;
 }
@@ -1048,7 +1052,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
                }
                nicvf_sq_add_hdr_subdesc(sq, hdr_qentry,
                                         seg_subdescs - 1, skb, seg_len);
-               sq->skbuff[hdr_qentry] = 0;
+               sq->skbuff[hdr_qentry] = (u64)NULL;
                qentry = nicvf_get_nxt_sqentry(sq, qentry);
 
                desc_cnt += seg_subdescs;
@@ -1062,6 +1066,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
        /* Inform HW to xmit all TSO segments */
        nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
                              skb_get_queue_mapping(skb), desc_cnt);
+       nic->drv_stats.tx_tso++;
        return 1;
 }
 
index 8341bdf755d1dfa8a4d288c43d7037fccf5bb6ea..f0937b7bfe9f476d914f9eb28ad040125b9750d9 100644 (file)
@@ -62,7 +62,7 @@
 #define SND_QUEUE_CNT          8
 #define CMP_QUEUE_CNT          8 /* Max of RCV and SND qcount */
 
-#define SND_QSIZE              SND_QUEUE_SIZE4
+#define SND_QSIZE              SND_QUEUE_SIZE2
 #define SND_QUEUE_LEN          (1ULL << (SND_QSIZE + 10))
 #define MAX_SND_QUEUE_LEN      (1ULL << (SND_QUEUE_SIZE6 + 10))
 #define SND_QUEUE_THRESH       2ULL
 /* Since timestamp not enabled, otherwise 2 */
 #define MAX_CQE_PER_PKT_XMIT           1
 
-#define CMP_QSIZE              CMP_QUEUE_SIZE4
+/* Keep CQ and SQ sizes same, if timestamping
+ * is enabled this equation will change.
+ */
+#define CMP_QSIZE              CMP_QUEUE_SIZE2
 #define CMP_QUEUE_LEN          (1ULL << (CMP_QSIZE + 10))
 #define CMP_QUEUE_CQE_THRESH   0
 #define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */
 
 #define MAX_CQES_FOR_TX                ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
                                 MAX_CQE_PER_PKT_XMIT)
-#define RQ_CQ_DROP             ((CMP_QUEUE_LEN - MAX_CQES_FOR_TX) / 256)
+/* Calculate number of CQEs to reserve for all SQEs.
+ * Its 1/256th level of CQ size.
+ * '+ 1' to account for pipelining
+ */
+#define RQ_CQ_DROP             ((256 / (CMP_QUEUE_LEN / \
+                                (CMP_QUEUE_LEN - MAX_CQES_FOR_TX))) + 1)
 
 /* Descriptor size in bytes */
 #define SND_QUEUE_DESC_SIZE    16
index 633ec05dfe0578b71825bf409df24371f58a776c..b961a89dc6264555553ee94484478b5dca9822dc 100644 (file)
@@ -673,7 +673,10 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
        bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
        bgx_flush_dmac_addrs(bgx, lmacid);
 
-       if (lmac->phydev)
+       if ((bgx->lmac_type != BGX_MODE_XFI) &&
+           (bgx->lmac_type != BGX_MODE_XLAUI) &&
+           (bgx->lmac_type != BGX_MODE_40G_KR) &&
+           (bgx->lmac_type != BGX_MODE_10G_KR) && lmac->phydev)
                phy_disconnect(lmac->phydev);
 
        lmac->phydev = NULL;
index 484eb8c374890ff951bf270935e7f45a7db23d18..c3c7db41819dfad26b521008c6c70148711ee019 100644 (file)
@@ -952,16 +952,23 @@ static int devlog_show(struct seq_file *seq, void *v)
                 * eventually have to put a format interpreter in here ...
                 */
                seq_printf(seq, "%10d  %15llu  %8s  %8s  ",
-                          e->seqno, e->timestamp,
+                          be32_to_cpu(e->seqno),
+                          be64_to_cpu(e->timestamp),
                           (e->level < ARRAY_SIZE(devlog_level_strings)
                            ? devlog_level_strings[e->level]
                            : "UNKNOWN"),
                           (e->facility < ARRAY_SIZE(devlog_facility_strings)
                            ? devlog_facility_strings[e->facility]
                            : "UNKNOWN"));
-               seq_printf(seq, e->fmt, e->params[0], e->params[1],
-                          e->params[2], e->params[3], e->params[4],
-                          e->params[5], e->params[6], e->params[7]);
+               seq_printf(seq, e->fmt,
+                          be32_to_cpu(e->params[0]),
+                          be32_to_cpu(e->params[1]),
+                          be32_to_cpu(e->params[2]),
+                          be32_to_cpu(e->params[3]),
+                          be32_to_cpu(e->params[4]),
+                          be32_to_cpu(e->params[5]),
+                          be32_to_cpu(e->params[6]),
+                          be32_to_cpu(e->params[7]));
        }
        return 0;
 }
@@ -1043,23 +1050,17 @@ static int devlog_open(struct inode *inode, struct file *file)
                return ret;
        }
 
-       /* Translate log multi-byte integral elements into host native format
-        * and determine where the first entry in the log is.
+       /* Find the earliest (lowest Sequence Number) log entry in the
+        * circular Device Log.
         */
        for (fseqno = ~((u32)0), index = 0; index < dinfo->nentries; index++) {
                struct fw_devlog_e *e = &dinfo->log[index];
-               int i;
                __u32 seqno;
 
                if (e->timestamp == 0)
                        continue;
 
-               e->timestamp = (__force __be64)be64_to_cpu(e->timestamp);
                seqno = be32_to_cpu(e->seqno);
-               for (i = 0; i < 8; i++)
-                       e->params[i] =
-                               (__force __be32)be32_to_cpu(e->params[i]);
-
                if (seqno < fseqno) {
                        fseqno = seqno;
                        dinfo->first = index;
@@ -2331,10 +2332,11 @@ int t4_setup_debugfs(struct adapter *adap)
                                        EXT_MEM1_SIZE_G(size));
                }
        } else {
-               if (i & EXT_MEM_ENABLE_F)
+               if (i & EXT_MEM_ENABLE_F) {
                        size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
                        add_debugfs_mem(adap, "mc", MEM_MC,
                                        EXT_MEM_SIZE_G(size));
+               }
        }
 
        de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap,
index da2004e2a74176959ece42065a26267aa2924a2b..918a8e42139b1f8ba9d95a4a9a1300c014324db8 100644 (file)
@@ -1170,7 +1170,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
                                                 wq_work_done,
                                                 0 /* dont unmask intr */,
                                                 0 /* dont reset intr timer */);
-               return rq_work_done;
+               return budget;
        }
 
        if (budget > 0)
@@ -1191,6 +1191,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
                        0 /* don't reset intr timer */);
 
        err = vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
+       enic_poll_unlock_napi(&enic->rq[cq_rq], napi);
 
        /* Buffer allocation failed. Stay in polling
         * mode so we can try to fill the ring again.
@@ -1208,7 +1209,6 @@ static int enic_poll(struct napi_struct *napi, int budget)
                napi_complete(napi);
                vnic_intr_unmask(&enic->intr[intr]);
        }
-       enic_poll_unlock_napi(&enic->rq[cq_rq], napi);
 
        return rq_work_done;
 }
index 2716e6f30d9a0949633b40dc9864196c7465fa3a..00e3a6b6b82254269aa7e0bf5d165f13d358594f 100644 (file)
@@ -620,6 +620,11 @@ enum be_if_flags {
                                         BE_IF_FLAGS_VLAN_PROMISCUOUS |\
                                         BE_IF_FLAGS_MCAST_PROMISCUOUS)
 
+#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\
+                       BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED)
+
+#define BE_IF_ALL_FILT_FLAGS   (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS)
+
 /* An RX interface is an object with one or more MAC addresses and
  * filtering capabilities. */
 struct be_cmd_req_if_create {
index 6f642426308c67399eac3abdb20ae6160ce41d2a..6ca693b03f33abbbdb6097544f2f4ee7f3928720 100644 (file)
@@ -273,6 +273,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        if (ether_addr_equal(addr->sa_data, netdev->dev_addr))
                return 0;
 
+       /* if device is not running, copy MAC to netdev->dev_addr */
+       if (!netif_running(netdev))
+               goto done;
+
        /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT
         * privilege or if PF did not provision the new MAC address.
         * On BE3, this cmd will always fail if the VF doesn't have the
@@ -307,9 +311,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
                status = -EPERM;
                goto err;
        }
-
-       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-       dev_info(dev, "MAC address changed to %pM\n", mac);
+done:
+       ether_addr_copy(netdev->dev_addr, addr->sa_data);
+       dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
        return 0;
 err:
        dev_warn(dev, "MAC address change to %pM failed\n", addr->sa_data);
@@ -2447,10 +2451,24 @@ static void be_eq_clean(struct be_eq_obj *eqo)
        be_eq_notify(eqo->adapter, eqo->q.id, false, true, num, 0);
 }
 
-static void be_rx_cq_clean(struct be_rx_obj *rxo)
+/* Free posted rx buffers that were not used */
+static void be_rxq_clean(struct be_rx_obj *rxo)
 {
-       struct be_rx_page_info *page_info;
        struct be_queue_info *rxq = &rxo->q;
+       struct be_rx_page_info *page_info;
+
+       while (atomic_read(&rxq->used) > 0) {
+               page_info = get_rx_page_info(rxo);
+               put_page(page_info->page);
+               memset(page_info, 0, sizeof(*page_info));
+       }
+       BUG_ON(atomic_read(&rxq->used));
+       rxq->tail = 0;
+       rxq->head = 0;
+}
+
+static void be_rx_cq_clean(struct be_rx_obj *rxo)
+{
        struct be_queue_info *rx_cq = &rxo->cq;
        struct be_rx_compl_info *rxcp;
        struct be_adapter *adapter = rxo->adapter;
@@ -2487,16 +2505,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
 
        /* After cleanup, leave the CQ in unarmed state */
        be_cq_notify(adapter, rx_cq->id, false, 0);
-
-       /* Then free posted rx buffers that were not used */
-       while (atomic_read(&rxq->used) > 0) {
-               page_info = get_rx_page_info(rxo);
-               put_page(page_info->page);
-               memset(page_info, 0, sizeof(*page_info));
-       }
-       BUG_ON(atomic_read(&rxq->used));
-       rxq->tail = 0;
-       rxq->head = 0;
 }
 
 static void be_tx_compl_clean(struct be_adapter *adapter)
@@ -2576,8 +2584,8 @@ static void be_evt_queues_destroy(struct be_adapter *adapter)
                        be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ);
                        napi_hash_del(&eqo->napi);
                        netif_napi_del(&eqo->napi);
+                       free_cpumask_var(eqo->affinity_mask);
                }
-               free_cpumask_var(eqo->affinity_mask);
                be_queue_free(adapter, &eqo->q);
        }
 }
@@ -2594,13 +2602,7 @@ static int be_evt_queues_create(struct be_adapter *adapter)
 
        for_all_evt_queues(adapter, eqo, i) {
                int numa_node = dev_to_node(&adapter->pdev->dev);
-               if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
-                       return -ENOMEM;
-               cpumask_set_cpu(cpumask_local_spread(i, numa_node),
-                               eqo->affinity_mask);
-               netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
-                              BE_NAPI_WEIGHT);
-               napi_hash_add(&eqo->napi);
+
                aic = &adapter->aic_obj[i];
                eqo->adapter = adapter;
                eqo->idx = i;
@@ -2616,6 +2618,14 @@ static int be_evt_queues_create(struct be_adapter *adapter)
                rc = be_cmd_eq_create(adapter, eqo);
                if (rc)
                        return rc;
+
+               if (!zalloc_cpumask_var(&eqo->affinity_mask, GFP_KERNEL))
+                       return -ENOMEM;
+               cpumask_set_cpu(cpumask_local_spread(i, numa_node),
+                               eqo->affinity_mask);
+               netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
+                              BE_NAPI_WEIGHT);
+               napi_hash_add(&eqo->napi);
        }
        return 0;
 }
@@ -3354,13 +3364,54 @@ static void be_rx_qs_destroy(struct be_adapter *adapter)
        for_all_rx_queues(adapter, rxo, i) {
                q = &rxo->q;
                if (q->created) {
+                       /* If RXQs are destroyed while in an "out of buffer"
+                        * state, there is a possibility of an HW stall on
+                        * Lancer. So, post 64 buffers to each queue to relieve
+                        * the "out of buffer" condition.
+                        * Make sure there's space in the RXQ before posting.
+                        */
+                       if (lancer_chip(adapter)) {
+                               be_rx_cq_clean(rxo);
+                               if (atomic_read(&q->used) == 0)
+                                       be_post_rx_frags(rxo, GFP_KERNEL,
+                                                        MAX_RX_POST);
+                       }
+
                        be_cmd_rxq_destroy(adapter, q);
                        be_rx_cq_clean(rxo);
+                       be_rxq_clean(rxo);
                }
                be_queue_free(adapter, q);
        }
 }
 
+static void be_disable_if_filters(struct be_adapter *adapter)
+{
+       be_cmd_pmac_del(adapter, adapter->if_handle,
+                       adapter->pmac_id[0], 0);
+
+       be_clear_uc_list(adapter);
+
+       /* The IFACE flags are enabled in the open path and cleared
+        * in the close path. When a VF gets detached from the host and
+        * assigned to a VM the following happens:
+        *      - VF's IFACE flags get cleared in the detach path
+        *      - IFACE create is issued by the VF in the attach path
+        * Due to a bug in the BE3/Skyhawk-R FW
+        * (Lancer FW doesn't have the bug), the IFACE capability flags
+        * specified along with the IFACE create cmd issued by a VF are not
+        * honoured by FW.  As a consequence, if a *new* driver
+        * (that enables/disables IFACE flags in open/close)
+        * is loaded in the host and an *old* driver is * used by a VM/VF,
+        * the IFACE gets created *without* the needed flags.
+        * To avoid this, disable RX-filter flags only for Lancer.
+        */
+       if (lancer_chip(adapter)) {
+               be_cmd_rx_filter(adapter, BE_IF_ALL_FILT_FLAGS, OFF);
+               adapter->if_flags &= ~BE_IF_ALL_FILT_FLAGS;
+       }
+}
+
 static int be_close(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -3373,6 +3424,8 @@ static int be_close(struct net_device *netdev)
        if (!(adapter->flags & BE_FLAGS_SETUP_DONE))
                return 0;
 
+       be_disable_if_filters(adapter);
+
        be_roce_dev_close(adapter);
 
        if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
@@ -3392,7 +3445,6 @@ static int be_close(struct net_device *netdev)
        be_tx_compl_clean(adapter);
 
        be_rx_qs_destroy(adapter);
-       be_clear_uc_list(adapter);
 
        for_all_evt_queues(adapter, eqo, i) {
                if (msix_enabled(adapter))
@@ -3477,6 +3529,31 @@ static int be_rx_qs_create(struct be_adapter *adapter)
        return 0;
 }
 
+static int be_enable_if_filters(struct be_adapter *adapter)
+{
+       int status;
+
+       status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON);
+       if (status)
+               return status;
+
+       /* For BE3 VFs, the PF programs the initial MAC address */
+       if (!(BEx_chip(adapter) && be_virtfn(adapter))) {
+               status = be_cmd_pmac_add(adapter, adapter->netdev->dev_addr,
+                                        adapter->if_handle,
+                                        &adapter->pmac_id[0], 0);
+               if (status)
+                       return status;
+       }
+
+       if (adapter->vlans_added)
+               be_vid_config(adapter);
+
+       be_set_rx_mode(adapter->netdev);
+
+       return 0;
+}
+
 static int be_open(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -3490,6 +3567,10 @@ static int be_open(struct net_device *netdev)
        if (status)
                goto err;
 
+       status = be_enable_if_filters(adapter);
+       if (status)
+               goto err;
+
        status = be_irq_register(adapter);
        if (status)
                goto err;
@@ -3686,16 +3767,6 @@ static void be_cancel_err_detection(struct be_adapter *adapter)
        }
 }
 
-static void be_mac_clear(struct be_adapter *adapter)
-{
-       if (adapter->pmac_id) {
-               be_cmd_pmac_del(adapter, adapter->if_handle,
-                               adapter->pmac_id[0], 0);
-               kfree(adapter->pmac_id);
-               adapter->pmac_id = NULL;
-       }
-}
-
 #ifdef CONFIG_BE2NET_VXLAN
 static void be_disable_vxlan_offloads(struct be_adapter *adapter)
 {
@@ -3770,8 +3841,8 @@ static int be_clear(struct be_adapter *adapter)
 #ifdef CONFIG_BE2NET_VXLAN
        be_disable_vxlan_offloads(adapter);
 #endif
-       /* delete the primary mac along with the uc-mac list */
-       be_mac_clear(adapter);
+       kfree(adapter->pmac_id);
+       adapter->pmac_id = NULL;
 
        be_cmd_if_destroy(adapter, adapter->if_handle,  0);
 
@@ -3782,25 +3853,11 @@ static int be_clear(struct be_adapter *adapter)
        return 0;
 }
 
-static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
-                       u32 cap_flags, u32 vf)
-{
-       u32 en_flags;
-
-       en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                  BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
-                  BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
-
-       en_flags &= cap_flags;
-
-       return be_cmd_if_create(adapter, cap_flags, en_flags, if_handle, vf);
-}
-
 static int be_vfs_if_create(struct be_adapter *adapter)
 {
        struct be_resources res = {0};
+       u32 cap_flags, en_flags, vf;
        struct be_vf_cfg *vf_cfg;
-       u32 cap_flags, vf;
        int status;
 
        /* If a FW profile exists, then cap_flags are updated */
@@ -3821,8 +3878,12 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                        }
                }
 
-               status = be_if_create(adapter, &vf_cfg->if_handle,
-                                     cap_flags, vf + 1);
+               en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
+                                       BE_IF_FLAGS_BROADCAST |
+                                       BE_IF_FLAGS_MULTICAST |
+                                       BE_IF_FLAGS_PASS_L3L4_ERRORS);
+               status = be_cmd_if_create(adapter, cap_flags, en_flags,
+                                         &vf_cfg->if_handle, vf + 1);
                if (status)
                        return status;
        }
@@ -4194,15 +4255,8 @@ static int be_mac_setup(struct be_adapter *adapter)
 
                memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
                memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
-       } else {
-               /* Maybe the HW was reset; dev_addr must be re-programmed */
-               memcpy(mac, adapter->netdev->dev_addr, ETH_ALEN);
        }
 
-       /* For BE3-R VFs, the PF programs the initial MAC address */
-       if (!(BEx_chip(adapter) && be_virtfn(adapter)))
-               be_cmd_pmac_add(adapter, mac, adapter->if_handle,
-                               &adapter->pmac_id[0], 0);
        return 0;
 }
 
@@ -4342,6 +4396,7 @@ static int be_func_init(struct be_adapter *adapter)
 static int be_setup(struct be_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
+       u32 en_flags;
        int status;
 
        status = be_func_init(adapter);
@@ -4364,8 +4419,11 @@ static int be_setup(struct be_adapter *adapter)
        if (status)
                goto err;
 
-       status = be_if_create(adapter, &adapter->if_handle,
-                             be_if_cap_flags(adapter), 0);
+       /* will enable all the needed filter flags in be_open() */
+       en_flags = BE_IF_FLAGS_RSS | BE_IF_FLAGS_DEFQ_RSS;
+       en_flags = en_flags & be_if_cap_flags(adapter);
+       status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags,
+                                 &adapter->if_handle, 0);
        if (status)
                goto err;
 
@@ -4391,11 +4449,6 @@ static int be_setup(struct be_adapter *adapter)
                dev_err(dev, "Please upgrade firmware to version >= 4.0\n");
        }
 
-       if (adapter->vlans_added)
-               be_vid_config(adapter);
-
-       be_set_rx_mode(adapter->netdev);
-
        status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
                                         adapter->rx_fc);
        if (status)
@@ -5121,7 +5174,7 @@ static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
        struct device *dev = &adapter->pdev->dev;
        int status;
 
-       if (lancer_chip(adapter) || BEx_chip(adapter))
+       if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter))
                return;
 
        if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
@@ -5168,7 +5221,7 @@ static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
-       if (lancer_chip(adapter) || BEx_chip(adapter))
+       if (lancer_chip(adapter) || BEx_chip(adapter) || be_is_mc(adapter))
                return;
 
        if (adapter->vxlan_port != port)
index 1eee73cccdf58deba85c810399930ffa55dfa03c..99d33e2d35e6c2c219fbd06f34546619a01a586d 100644 (file)
@@ -562,6 +562,7 @@ struct fec_enet_private {
 };
 
 void fec_ptp_init(struct platform_device *pdev);
+void fec_ptp_stop(struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
 int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
index 1f89c59b43535f9b65e946c7468cb1fcb13a2022..271bb5862346ede352473f0837fb76e0a5ac7163 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/pm_runtime.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
@@ -77,6 +78,7 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
 #define FEC_ENET_RAEM_V        0x8
 #define FEC_ENET_RAFL_V        0x8
 #define FEC_ENET_OPD_V 0xFFF0
+#define FEC_MDIO_PM_TIMEOUT  100 /* ms */
 
 static struct platform_device_id fec_devtype[] = {
        {
@@ -1767,7 +1769,13 @@ static void fec_enet_adjust_link(struct net_device *ndev)
 static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
        struct fec_enet_private *fep = bus->priv;
+       struct device *dev = &fep->pdev->dev;
        unsigned long time_left;
+       int ret = 0;
+
+       ret = pm_runtime_get_sync(dev);
+       if (IS_ERR_VALUE(ret))
+               return ret;
 
        fep->mii_timeout = 0;
        init_completion(&fep->mdio_done);
@@ -1783,18 +1791,30 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        if (time_left == 0) {
                fep->mii_timeout = 1;
                netdev_err(fep->netdev, "MDIO read timeout\n");
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto out;
        }
 
-       /* return value */
-       return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
+       ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
+
+out:
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
 }
 
 static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
                           u16 value)
 {
        struct fec_enet_private *fep = bus->priv;
+       struct device *dev = &fep->pdev->dev;
        unsigned long time_left;
+       int ret = 0;
+
+       ret = pm_runtime_get_sync(dev);
+       if (IS_ERR_VALUE(ret))
+               return ret;
 
        fep->mii_timeout = 0;
        init_completion(&fep->mdio_done);
@@ -1811,10 +1831,13 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        if (time_left == 0) {
                fep->mii_timeout = 1;
                netdev_err(fep->netdev, "MDIO write timeout\n");
-               return -ETIMEDOUT;
+               ret  = -ETIMEDOUT;
        }
 
-       return 0;
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
 }
 
 static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
@@ -1826,9 +1849,6 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                ret = clk_prepare_enable(fep->clk_ahb);
                if (ret)
                        return ret;
-               ret = clk_prepare_enable(fep->clk_ipg);
-               if (ret)
-                       goto failed_clk_ipg;
                if (fep->clk_enet_out) {
                        ret = clk_prepare_enable(fep->clk_enet_out);
                        if (ret)
@@ -1852,7 +1872,6 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                }
        } else {
                clk_disable_unprepare(fep->clk_ahb);
-               clk_disable_unprepare(fep->clk_ipg);
                if (fep->clk_enet_out)
                        clk_disable_unprepare(fep->clk_enet_out);
                if (fep->clk_ptp) {
@@ -1874,8 +1893,6 @@ failed_clk_ptp:
        if (fep->clk_enet_out)
                clk_disable_unprepare(fep->clk_enet_out);
 failed_clk_enet_out:
-               clk_disable_unprepare(fep->clk_ipg);
-failed_clk_ipg:
                clk_disable_unprepare(fep->clk_ahb);
 
        return ret;
@@ -2847,10 +2864,14 @@ fec_enet_open(struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        int ret;
 
+       ret = pm_runtime_get_sync(&fep->pdev->dev);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
        pinctrl_pm_select_default_state(&fep->pdev->dev);
        ret = fec_enet_clk_enable(ndev, true);
        if (ret)
-               return ret;
+               goto clk_enable;
 
        /* I should reset the ring buffers here, but I don't yet know
         * a simple way to do that.
@@ -2881,6 +2902,9 @@ err_enet_mii_probe:
        fec_enet_free_buffers(ndev);
 err_enet_alloc:
        fec_enet_clk_enable(ndev, false);
+clk_enable:
+       pm_runtime_mark_last_busy(&fep->pdev->dev);
+       pm_runtime_put_autosuspend(&fep->pdev->dev);
        pinctrl_pm_select_sleep_state(&fep->pdev->dev);
        return ret;
 }
@@ -2903,6 +2927,9 @@ fec_enet_close(struct net_device *ndev)
 
        fec_enet_clk_enable(ndev, false);
        pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+       pm_runtime_mark_last_busy(&fep->pdev->dev);
+       pm_runtime_put_autosuspend(&fep->pdev->dev);
+
        fec_enet_free_buffers(ndev);
 
        return 0;
@@ -3115,8 +3142,8 @@ static int fec_enet_init(struct net_device *ndev)
                        fep->bufdesc_size;
 
        /* Allocate memory for buffer descriptors. */
-       cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
-                                     GFP_KERNEL);
+       cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma,
+                                      GFP_KERNEL);
        if (!cbd_base) {
                return -ENOMEM;
        }
@@ -3388,6 +3415,10 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_clk;
 
+       ret = clk_prepare_enable(fep->clk_ipg);
+       if (ret)
+               goto failed_clk_ipg;
+
        fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");
        if (!IS_ERR(fep->reg_phy)) {
                ret = regulator_enable(fep->reg_phy);
@@ -3400,6 +3431,12 @@ fec_probe(struct platform_device *pdev)
                fep->reg_phy = NULL;
        }
 
+       pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        fec_reset_phy(pdev);
 
        if (fep->bufdesc_ex)
@@ -3447,6 +3484,10 @@ fec_probe(struct platform_device *pdev)
 
        fep->rx_copybreak = COPYBREAK_DEFAULT;
        INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
+
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
+
        return 0;
 
 failed_register:
@@ -3454,9 +3495,12 @@ failed_register:
 failed_mii_init:
 failed_irq:
 failed_init:
+       fec_ptp_stop(pdev);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
 failed_regulator:
+       clk_disable_unprepare(fep->clk_ipg);
+failed_clk_ipg:
        fec_enet_clk_enable(ndev, false);
 failed_clk:
 failed_phy:
@@ -3473,14 +3517,12 @@ fec_drv_remove(struct platform_device *pdev)
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
 
-       cancel_delayed_work_sync(&fep->time_keep);
        cancel_work_sync(&fep->tx_timeout_work);
+       fec_ptp_stop(pdev);
        unregister_netdev(ndev);
        fec_enet_mii_remove(fep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
-       if (fep->ptp_clock)
-               ptp_clock_unregister(fep->ptp_clock);
        of_node_put(fep->phy_node);
        free_netdev(ndev);
 
@@ -3568,7 +3610,28 @@ failed_clk:
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(fec_pm_ops, fec_suspend, fec_resume);
+static int __maybe_unused fec_runtime_suspend(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       clk_disable_unprepare(fep->clk_ipg);
+
+       return 0;
+}
+
+static int __maybe_unused fec_runtime_resume(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       return clk_prepare_enable(fep->clk_ipg);
+}
+
+static const struct dev_pm_ops fec_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(fec_suspend, fec_resume)
+       SET_RUNTIME_PM_OPS(fec_runtime_suspend, fec_runtime_resume, NULL)
+};
 
 static struct platform_driver fec_driver = {
        .driver = {
index a15663ad7f5e98c64a1f6e0912163bee578c938b..f457a23d0bfbd4149332d9bb93506891670ca36d 100644 (file)
@@ -604,6 +604,16 @@ void fec_ptp_init(struct platform_device *pdev)
        schedule_delayed_work(&fep->time_keep, HZ);
 }
 
+void fec_ptp_stop(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct fec_enet_private *fep = netdev_priv(ndev);
+
+       cancel_delayed_work_sync(&fep->time_keep);
+       if (fep->ptp_clock)
+               ptp_clock_unregister(fep->ptp_clock);
+}
+
 /**
  * fec_ptp_check_pps_event
  * @fep: the fec_enet_private structure handle
index 56316db6c5a674fd1d17ef20e8db3747950cf71e..cf8e54652df95266e24a5d6d64ed67c00336f67b 100644 (file)
@@ -586,7 +586,8 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        frag = skb_shinfo(skb)->frags;
        while (nr_frags) {
                CBDC_SC(bdp,
-                       BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+                       BD_ENET_TX_STATS | BD_ENET_TX_INTR | BD_ENET_TX_LAST |
+                       BD_ENET_TX_TC);
                CBDS_SC(bdp, BD_ENET_TX_READY);
 
                if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
index b34214e2df5f6e55bdbb29e6a8016c139e74345c..016743e355de31984d57904e802d69e6703ea5e4 100644 (file)
@@ -110,7 +110,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
 }
 
 #define FEC_NAPI_RX_EVENT_MSK  (FEC_ENET_RXF | FEC_ENET_RXB)
-#define FEC_NAPI_TX_EVENT_MSK  (FEC_ENET_TXF | FEC_ENET_TXB)
+#define FEC_NAPI_TX_EVENT_MSK  (FEC_ENET_TXF)
 #define FEC_RX_EVENT           (FEC_ENET_RXF)
 #define FEC_TX_EVENT           (FEC_ENET_TXF)
 #define FEC_ERR_EVENT_MSK      (FEC_ENET_HBERR | FEC_ENET_BABR | \
index ff875028fdff5e1723c618f721658971cd051603..10b3bbbbac8e10e89c47b2d50bb661cc80ad616b 100644 (file)
@@ -565,22 +565,6 @@ static void gfar_ints_enable(struct gfar_private *priv)
        }
 }
 
-static void lock_tx_qs(struct gfar_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_lock(&priv->tx_queue[i]->txlock);
-}
-
-static void unlock_tx_qs(struct gfar_private *priv)
-{
-       int i;
-
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_unlock(&priv->tx_queue[i]->txlock);
-}
-
 static int gfar_alloc_tx_queues(struct gfar_private *priv)
 {
        int i;
@@ -1376,7 +1360,6 @@ static int gfar_probe(struct platform_device *ofdev)
        priv->dev = &ofdev->dev;
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
-       spin_lock_init(&priv->bflock);
        INIT_WORK(&priv->reset_task, gfar_reset_task);
 
        platform_set_drvdata(ofdev, priv);
@@ -1470,9 +1453,8 @@ static int gfar_probe(struct platform_device *ofdev)
                goto register_fail;
        }
 
-       device_init_wakeup(&dev->dev,
-                          priv->device_flags &
-                          FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+       device_set_wakeup_capable(&dev->dev, priv->device_flags &
+                                 FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
        /* fill out IRQ number and name fields */
        for (i = 0; i < priv->num_grps; i++) {
@@ -1540,48 +1522,37 @@ static int gfar_suspend(struct device *dev)
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        u32 tempval;
-
        int magic_packet = priv->wol_en &&
                           (priv->device_flags &
                            FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
+       if (!netif_running(ndev))
+               return 0;
+
+       disable_napi(priv);
+       netif_tx_lock(ndev);
        netif_device_detach(ndev);
+       netif_tx_unlock(ndev);
 
-       if (netif_running(ndev)) {
+       gfar_halt(priv);
 
-               local_irq_save(flags);
-               lock_tx_qs(priv);
+       if (magic_packet) {
+               /* Enable interrupt on Magic Packet */
+               gfar_write(&regs->imask, IMASK_MAG);
 
-               gfar_halt_nodisable(priv);
+               /* Enable Magic Packet mode */
+               tempval = gfar_read(&regs->maccfg2);
+               tempval |= MACCFG2_MPEN;
+               gfar_write(&regs->maccfg2, tempval);
 
-               /* Disable Tx, and Rx if wake-on-LAN is disabled. */
+               /* re-enable the Rx block */
                tempval = gfar_read(&regs->maccfg1);
-
-               tempval &= ~MACCFG1_TX_EN;
-
-               if (!magic_packet)
-                       tempval &= ~MACCFG1_RX_EN;
-
+               tempval |= MACCFG1_RX_EN;
                gfar_write(&regs->maccfg1, tempval);
 
-               unlock_tx_qs(priv);
-               local_irq_restore(flags);
-
-               disable_napi(priv);
-
-               if (magic_packet) {
-                       /* Enable interrupt on Magic Packet */
-                       gfar_write(&regs->imask, IMASK_MAG);
-
-                       /* Enable Magic Packet mode */
-                       tempval = gfar_read(&regs->maccfg2);
-                       tempval |= MACCFG2_MPEN;
-                       gfar_write(&regs->maccfg2, tempval);
-               } else {
-                       phy_stop(priv->phydev);
-               }
+       } else {
+               phy_stop(priv->phydev);
        }
 
        return 0;
@@ -1592,37 +1563,26 @@ static int gfar_resume(struct device *dev)
        struct gfar_private *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->ndev;
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        u32 tempval;
        int magic_packet = priv->wol_en &&
                           (priv->device_flags &
                            FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
-       if (!netif_running(ndev)) {
-               netif_device_attach(ndev);
+       if (!netif_running(ndev))
                return 0;
-       }
 
-       if (!magic_packet && priv->phydev)
+       if (magic_packet) {
+               /* Disable Magic Packet mode */
+               tempval = gfar_read(&regs->maccfg2);
+               tempval &= ~MACCFG2_MPEN;
+               gfar_write(&regs->maccfg2, tempval);
+       } else {
                phy_start(priv->phydev);
-
-       /* Disable Magic Packet mode, in case something
-        * else woke us up.
-        */
-       local_irq_save(flags);
-       lock_tx_qs(priv);
-
-       tempval = gfar_read(&regs->maccfg2);
-       tempval &= ~MACCFG2_MPEN;
-       gfar_write(&regs->maccfg2, tempval);
+       }
 
        gfar_start(priv);
 
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
-
        netif_device_attach(ndev);
-
        enable_napi(priv);
 
        return 0;
@@ -2045,7 +2005,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                /* Install our interrupt handlers for Error,
                 * Transmit, and Receive
                 */
-               err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0,
+               err = request_irq(gfar_irq(grp, ER)->irq, gfar_error,
+                                 IRQF_NO_SUSPEND,
                                  gfar_irq(grp, ER)->name, grp);
                if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
@@ -2068,7 +2029,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp)
                        goto rx_irq_fail;
                }
        } else {
-               err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
+               err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt,
+                                 IRQF_NO_SUSPEND,
                                  gfar_irq(grp, TX)->name, grp);
                if (err < 0) {
                        netif_err(priv, intr, dev, "Can't get IRQ %d\n",
@@ -2140,6 +2102,11 @@ int startup_gfar(struct net_device *ndev)
        /* Start Rx/Tx DMA and enable the interrupts */
        gfar_start(priv);
 
+       /* force link state update after mac reset */
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+
        phy_start(priv->phydev);
 
        enable_napi(priv);
@@ -2169,8 +2136,6 @@ static int gfar_enet_open(struct net_device *dev)
        if (err)
                return err;
 
-       device_set_wakeup_enable(&dev->dev, priv->wol_en);
-
        return err;
 }
 
index daa1d37de6427b93a756843074c5d2e5c1961467..5545e41033686e3d7443811e2ec1caa2da2f5be4 100644 (file)
@@ -1145,9 +1145,6 @@ struct gfar_private {
        int oldduplex;
        int oldlink;
 
-       /* Bitfield update lock */
-       spinlock_t bflock;
-
        uint32_t msg_enable;
 
        struct work_struct reset_task;
index fda12fb32ec77a8538a0f1d1370d2e653c91856c..5b90fcf96265aec4a6daa1f28135ef2fa06a0752 100644 (file)
@@ -653,7 +653,6 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       unsigned long flags;
 
        if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
            wol->wolopts != 0)
@@ -664,9 +663,7 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
        device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC);
 
-       spin_lock_irqsave(&priv->bflock, flags);
-       priv->wol_en =  !!device_may_wakeup(&dev->dev);
-       spin_unlock_irqrestore(&priv->bflock, flags);
+       priv->wol_en = !!device_may_wakeup(&dev->dev);
 
        return 0;
 }
@@ -903,27 +900,6 @@ static int gfar_check_filer_hardware(struct gfar_private *priv)
        return 0;
 }
 
-static int gfar_comp_asc(const void *a, const void *b)
-{
-       return memcmp(a, b, 4);
-}
-
-static int gfar_comp_desc(const void *a, const void *b)
-{
-       return -memcmp(a, b, 4);
-}
-
-static void gfar_swap(void *a, void *b, int size)
-{
-       u32 *_a = a;
-       u32 *_b = b;
-
-       swap(_a[0], _b[0]);
-       swap(_a[1], _b[1]);
-       swap(_a[2], _b[2]);
-       swap(_a[3], _b[3]);
-}
-
 /* Write a mask to filer cache */
 static void gfar_set_mask(u32 mask, struct filer_table *tab)
 {
@@ -1273,310 +1249,6 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
        return 0;
 }
 
-/* Copy size filer entries */
-static void gfar_copy_filer_entries(struct gfar_filer_entry dst[0],
-                                   struct gfar_filer_entry src[0], s32 size)
-{
-       while (size > 0) {
-               size--;
-               dst[size].ctrl = src[size].ctrl;
-               dst[size].prop = src[size].prop;
-       }
-}
-
-/* Delete the contents of the filer-table between start and end
- * and collapse them
- */
-static int gfar_trim_filer_entries(u32 begin, u32 end, struct filer_table *tab)
-{
-       int length;
-
-       if (end > MAX_FILER_CACHE_IDX || end < begin)
-               return -EINVAL;
-
-       end++;
-       length = end - begin;
-
-       /* Copy */
-       while (end < tab->index) {
-               tab->fe[begin].ctrl = tab->fe[end].ctrl;
-               tab->fe[begin++].prop = tab->fe[end++].prop;
-
-       }
-       /* Fill up with don't cares */
-       while (begin < tab->index) {
-               tab->fe[begin].ctrl = 0x60;
-               tab->fe[begin].prop = 0xFFFFFFFF;
-               begin++;
-       }
-
-       tab->index -= length;
-       return 0;
-}
-
-/* Make space on the wanted location */
-static int gfar_expand_filer_entries(u32 begin, u32 length,
-                                    struct filer_table *tab)
-{
-       if (length == 0 || length + tab->index > MAX_FILER_CACHE_IDX ||
-           begin > MAX_FILER_CACHE_IDX)
-               return -EINVAL;
-
-       gfar_copy_filer_entries(&(tab->fe[begin + length]), &(tab->fe[begin]),
-                               tab->index - length + 1);
-
-       tab->index += length;
-       return 0;
-}
-
-static int gfar_get_next_cluster_start(int start, struct filer_table *tab)
-{
-       for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
-            start++) {
-               if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
-                   (RQFCR_AND | RQFCR_CLE))
-                       return start;
-       }
-       return -1;
-}
-
-static int gfar_get_next_cluster_end(int start, struct filer_table *tab)
-{
-       for (; (start < tab->index) && (start < MAX_FILER_CACHE_IDX - 1);
-            start++) {
-               if ((tab->fe[start].ctrl & (RQFCR_AND | RQFCR_CLE)) ==
-                   (RQFCR_CLE))
-                       return start;
-       }
-       return -1;
-}
-
-/* Uses hardwares clustering option to reduce
- * the number of filer table entries
- */
-static void gfar_cluster_filer(struct filer_table *tab)
-{
-       s32 i = -1, j, iend, jend;
-
-       while ((i = gfar_get_next_cluster_start(++i, tab)) != -1) {
-               j = i;
-               while ((j = gfar_get_next_cluster_start(++j, tab)) != -1) {
-                       /* The cluster entries self and the previous one
-                        * (a mask) must be identical!
-                        */
-                       if (tab->fe[i].ctrl != tab->fe[j].ctrl)
-                               break;
-                       if (tab->fe[i].prop != tab->fe[j].prop)
-                               break;
-                       if (tab->fe[i - 1].ctrl != tab->fe[j - 1].ctrl)
-                               break;
-                       if (tab->fe[i - 1].prop != tab->fe[j - 1].prop)
-                               break;
-                       iend = gfar_get_next_cluster_end(i, tab);
-                       jend = gfar_get_next_cluster_end(j, tab);
-                       if (jend == -1 || iend == -1)
-                               break;
-
-                       /* First we make some free space, where our cluster
-                        * element should be. Then we copy it there and finally
-                        * delete in from its old location.
-                        */
-                       if (gfar_expand_filer_entries(iend, (jend - j), tab) ==
-                           -EINVAL)
-                               break;
-
-                       gfar_copy_filer_entries(&(tab->fe[iend + 1]),
-                                               &(tab->fe[jend + 1]), jend - j);
-
-                       if (gfar_trim_filer_entries(jend - 1,
-                                                   jend + (jend - j),
-                                                   tab) == -EINVAL)
-                               return;
-
-                       /* Mask out cluster bit */
-                       tab->fe[iend].ctrl &= ~(RQFCR_CLE);
-               }
-       }
-}
-
-/* Swaps the masked bits of a1<>a2 and b1<>b2 */
-static void gfar_swap_bits(struct gfar_filer_entry *a1,
-                          struct gfar_filer_entry *a2,
-                          struct gfar_filer_entry *b1,
-                          struct gfar_filer_entry *b2, u32 mask)
-{
-       u32 temp[4];
-       temp[0] = a1->ctrl & mask;
-       temp[1] = a2->ctrl & mask;
-       temp[2] = b1->ctrl & mask;
-       temp[3] = b2->ctrl & mask;
-
-       a1->ctrl &= ~mask;
-       a2->ctrl &= ~mask;
-       b1->ctrl &= ~mask;
-       b2->ctrl &= ~mask;
-
-       a1->ctrl |= temp[1];
-       a2->ctrl |= temp[0];
-       b1->ctrl |= temp[3];
-       b2->ctrl |= temp[2];
-}
-
-/* Generate a list consisting of masks values with their start and
- * end of validity and block as indicator for parts belonging
- * together (glued by ANDs) in mask_table
- */
-static u32 gfar_generate_mask_table(struct gfar_mask_entry *mask_table,
-                                   struct filer_table *tab)
-{
-       u32 i, and_index = 0, block_index = 1;
-
-       for (i = 0; i < tab->index; i++) {
-
-               /* LSByte of control = 0 sets a mask */
-               if (!(tab->fe[i].ctrl & 0xF)) {
-                       mask_table[and_index].mask = tab->fe[i].prop;
-                       mask_table[and_index].start = i;
-                       mask_table[and_index].block = block_index;
-                       if (and_index >= 1)
-                               mask_table[and_index - 1].end = i - 1;
-                       and_index++;
-               }
-               /* cluster starts and ends will be separated because they should
-                * hold their position
-                */
-               if (tab->fe[i].ctrl & RQFCR_CLE)
-                       block_index++;
-               /* A not set AND indicates the end of a depended block */
-               if (!(tab->fe[i].ctrl & RQFCR_AND))
-                       block_index++;
-       }
-
-       mask_table[and_index - 1].end = i - 1;
-
-       return and_index;
-}
-
-/* Sorts the entries of mask_table by the values of the masks.
- * Important: The 0xFF80 flags of the first and last entry of a
- * block must hold their position (which queue, CLusterEnable, ReJEct,
- * AND)
- */
-static void gfar_sort_mask_table(struct gfar_mask_entry *mask_table,
-                                struct filer_table *temp_table, u32 and_index)
-{
-       /* Pointer to compare function (_asc or _desc) */
-       int (*gfar_comp)(const void *, const void *);
-
-       u32 i, size = 0, start = 0, prev = 1;
-       u32 old_first, old_last, new_first, new_last;
-
-       gfar_comp = &gfar_comp_desc;
-
-       for (i = 0; i < and_index; i++) {
-               if (prev != mask_table[i].block) {
-                       old_first = mask_table[start].start + 1;
-                       old_last = mask_table[i - 1].end;
-                       sort(mask_table + start, size,
-                            sizeof(struct gfar_mask_entry),
-                            gfar_comp, &gfar_swap);
-
-                       /* Toggle order for every block. This makes the
-                        * thing more efficient!
-                        */
-                       if (gfar_comp == gfar_comp_desc)
-                               gfar_comp = &gfar_comp_asc;
-                       else
-                               gfar_comp = &gfar_comp_desc;
-
-                       new_first = mask_table[start].start + 1;
-                       new_last = mask_table[i - 1].end;
-
-                       gfar_swap_bits(&temp_table->fe[new_first],
-                                      &temp_table->fe[old_first],
-                                      &temp_table->fe[new_last],
-                                      &temp_table->fe[old_last],
-                                      RQFCR_QUEUE | RQFCR_CLE |
-                                      RQFCR_RJE | RQFCR_AND);
-
-                       start = i;
-                       size = 0;
-               }
-               size++;
-               prev = mask_table[i].block;
-       }
-}
-
-/* Reduces the number of masks needed in the filer table to save entries
- * This is done by sorting the masks of a depended block. A depended block is
- * identified by gluing ANDs or CLE. The sorting order toggles after every
- * block. Of course entries in scope of a mask must change their location with
- * it.
- */
-static int gfar_optimize_filer_masks(struct filer_table *tab)
-{
-       struct filer_table *temp_table;
-       struct gfar_mask_entry *mask_table;
-
-       u32 and_index = 0, previous_mask = 0, i = 0, j = 0, size = 0;
-       s32 ret = 0;
-
-       /* We need a copy of the filer table because
-        * we want to change its order
-        */
-       temp_table = kmemdup(tab, sizeof(*temp_table), GFP_KERNEL);
-       if (temp_table == NULL)
-               return -ENOMEM;
-
-       mask_table = kcalloc(MAX_FILER_CACHE_IDX / 2 + 1,
-                            sizeof(struct gfar_mask_entry), GFP_KERNEL);
-
-       if (mask_table == NULL) {
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       and_index = gfar_generate_mask_table(mask_table, tab);
-
-       gfar_sort_mask_table(mask_table, temp_table, and_index);
-
-       /* Now we can copy the data from our duplicated filer table to
-        * the real one in the order the mask table says
-        */
-       for (i = 0; i < and_index; i++) {
-               size = mask_table[i].end - mask_table[i].start + 1;
-               gfar_copy_filer_entries(&(tab->fe[j]),
-                               &(temp_table->fe[mask_table[i].start]), size);
-               j += size;
-       }
-
-       /* And finally we just have to check for duplicated masks and drop the
-        * second ones
-        */
-       for (i = 0; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
-               if (tab->fe[i].ctrl == 0x80) {
-                       previous_mask = i++;
-                       break;
-               }
-       }
-       for (; i < tab->index && i < MAX_FILER_CACHE_IDX; i++) {
-               if (tab->fe[i].ctrl == 0x80) {
-                       if (tab->fe[i].prop == tab->fe[previous_mask].prop) {
-                               /* Two identical ones found!
-                                * So drop the second one!
-                                */
-                               gfar_trim_filer_entries(i, i, tab);
-                       } else
-                               /* Not identical! */
-                               previous_mask = i;
-               }
-       }
-
-       kfree(mask_table);
-end:   kfree(temp_table);
-       return ret;
-}
-
 /* Write the bit-pattern from software's buffer to hardware registers */
 static int gfar_write_filer_table(struct gfar_private *priv,
                                  struct filer_table *tab)
@@ -1586,11 +1258,10 @@ static int gfar_write_filer_table(struct gfar_private *priv,
                return -EBUSY;
 
        /* Fill regular entries */
-       for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].prop);
-            i++)
+       for (; i < MAX_FILER_IDX && (tab->fe[i].ctrl | tab->fe[i].prop); i++)
                gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop);
        /* Fill the rest with fall-troughs */
-       for (; i < MAX_FILER_IDX - 1; i++)
+       for (; i < MAX_FILER_IDX; i++)
                gfar_write_filer(priv, i, 0x60, 0xFFFFFFFF);
        /* Last entry must be default accept
         * because that's what people expect
@@ -1624,7 +1295,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
 {
        struct ethtool_flow_spec_container *j;
        struct filer_table *tab;
-       s32 i = 0;
        s32 ret = 0;
 
        /* So index is set to zero, too! */
@@ -1649,17 +1319,6 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
                }
        }
 
-       i = tab->index;
-
-       /* Optimizations to save entries */
-       gfar_cluster_filer(tab);
-       gfar_optimize_filer_masks(tab);
-
-       pr_debug("\tSummary:\n"
-                "\tData on hardware: %d\n"
-                "\tCompression rate: %d%%\n",
-                tab->index, 100 - (100 * tab->index) / i);
-
        /* Write everything to hardware */
        ret = gfar_write_filer_table(priv, tab);
        if (ret == -EBUSY) {
@@ -1725,13 +1384,14 @@ static int gfar_add_cls(struct gfar_private *priv,
        }
 
 process:
+       priv->rx_list.count++;
        ret = gfar_process_filer_changes(priv);
        if (ret)
                goto clean_list;
-       priv->rx_list.count++;
        return ret;
 
 clean_list:
+       priv->rx_list.count--;
        list_del(&temp->list);
 clean_mem:
        kfree(temp);
index 982fdcdc795b4752a2fbe65e71ed76ee197ad5de..b5b2925103ec10c1e835429c2ab7d2efee093838 100644 (file)
@@ -216,7 +216,7 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring,
 
 static inline bool fm10k_page_is_reserved(struct page *page)
 {
-       return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+       return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
 }
 
 static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer,
index 2f70a9b152bd1789349d9c4d995852e95be1e70d..830466c49987cfbf1ad25f6d9bc01e4f7f0d0454 100644 (file)
@@ -6566,7 +6566,7 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring,
 
 static inline bool igb_page_is_reserved(struct page *page)
 {
-       return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+       return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
 }
 
 static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
index 9aa6104e34ea8e2bd93994e4d8291763014162b8..ae21e0b06c3ad40a54093c8966fcfa711f188cfb 100644 (file)
@@ -1832,7 +1832,7 @@ static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring,
 
 static inline bool ixgbe_page_is_reserved(struct page *page)
 {
-       return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+       return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
 }
 
 /**
index e71cdde9cb017aecab834d2f2d9c5d4821c3d42e..1d7b00b038a2ea8c3bdd9394ad3d4988ccee04c8 100644 (file)
@@ -765,7 +765,7 @@ static void ixgbevf_reuse_rx_page(struct ixgbevf_ring *rx_ring,
 
 static inline bool ixgbevf_page_is_reserved(struct page *page)
 {
-       return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+       return (page_to_nid(page) != numa_mem_id()) || page_is_pfmemalloc(page);
 }
 
 /**
index 370e20ed224c5c76eaca92954be5800d09d81ada..62e48bc0cb23ba98ed2cb2c447af288bd1c3906d 100644 (file)
@@ -1462,7 +1462,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                     struct mvneta_rx_queue *rxq)
 {
        struct net_device *dev = pp->dev;
-       int rx_done, rx_filled;
+       int rx_done;
        u32 rcvd_pkts = 0;
        u32 rcvd_bytes = 0;
 
@@ -1473,7 +1473,6 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                rx_todo = rx_done;
 
        rx_done = 0;
-       rx_filled = 0;
 
        /* Fairness NAPI loop */
        while (rx_done < rx_todo) {
@@ -1484,7 +1483,6 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                int rx_bytes, err;
 
                rx_done++;
-               rx_filled++;
                rx_status = rx_desc->status;
                rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
                data = (unsigned char *)rx_desc->buf_cookie;
@@ -1524,6 +1522,14 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                        continue;
                }
 
+               /* Refill processing */
+               err = mvneta_rx_refill(pp, rx_desc);
+               if (err) {
+                       netdev_err(dev, "Linux processing - Can't refill\n");
+                       rxq->missed++;
+                       goto err_drop_frame;
+               }
+
                skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size);
                if (!skb)
                        goto err_drop_frame;
@@ -1543,14 +1549,6 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
                mvneta_rx_csum(pp, rx_status, skb);
 
                napi_gro_receive(&pp->napi, skb);
-
-               /* Refill processing */
-               err = mvneta_rx_refill(pp, rx_desc);
-               if (err) {
-                       netdev_err(dev, "Linux processing - Can't refill\n");
-                       rxq->missed++;
-                       rx_filled--;
-               }
        }
 
        if (rcvd_pkts) {
@@ -1563,7 +1561,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
        }
 
        /* Update rxq management counters */
-       mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_filled);
+       mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
 
        return rx_done;
 }
index 3e8b1bfb1f2e316212bd9b60fa06522ca4dc68db..d9884fd15b453e2486177d58b7fc40bcd5aaf7cc 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/of_address.h>
 #include <linux/phy.h>
 #include <linux/clk.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
 #include <uapi/linux/ppp_defs.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 
 /* Coalescing */
 #define MVPP2_TXDONE_COAL_PKTS_THRESH  15
+#define MVPP2_TXDONE_HRTIMER_PERIOD_NS 1000000UL
 #define MVPP2_RX_COAL_PKTS             32
 #define MVPP2_RX_COAL_USEC             100
 
@@ -660,6 +663,14 @@ struct mvpp2_pcpu_stats {
        u64     tx_bytes;
 };
 
+/* Per-CPU port control */
+struct mvpp2_port_pcpu {
+       struct hrtimer tx_done_timer;
+       bool timer_scheduled;
+       /* Tasklet for egress finalization */
+       struct tasklet_struct tx_done_tasklet;
+};
+
 struct mvpp2_port {
        u8 id;
 
@@ -679,6 +690,9 @@ struct mvpp2_port {
        u32 pending_cause_rx;
        struct napi_struct napi;
 
+       /* Per-CPU port control */
+       struct mvpp2_port_pcpu __percpu *pcpu;
+
        /* Flags */
        unsigned long flags;
 
@@ -776,6 +790,9 @@ struct mvpp2_txq_pcpu {
        /* Array of transmitted skb */
        struct sk_buff **tx_skb;
 
+       /* Array of transmitted buffers' physical addresses */
+       dma_addr_t *tx_buffs;
+
        /* Index of last TX DMA descriptor that was inserted */
        int txq_put_index;
 
@@ -913,8 +930,6 @@ struct mvpp2_bm_pool {
        /* Occupied buffers indicator */
        atomic_t in_use;
        int in_use_thresh;
-
-       spinlock_t lock;
 };
 
 struct mvpp2_buff_hdr {
@@ -963,9 +978,13 @@ static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
 }
 
 static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu,
-                             struct sk_buff *skb)
+                             struct sk_buff *skb,
+                             struct mvpp2_tx_desc *tx_desc)
 {
        txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb;
+       if (skb)
+               txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] =
+                                                        tx_desc->buf_phys_addr;
        txq_pcpu->txq_put_index++;
        if (txq_pcpu->txq_put_index == txq_pcpu->size)
                txq_pcpu->txq_put_index = 0;
@@ -3376,7 +3395,6 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev,
        bm_pool->pkt_size = 0;
        bm_pool->buf_num = 0;
        atomic_set(&bm_pool->in_use, 0);
-       spin_lock_init(&bm_pool->lock);
 
        return 0;
 }
@@ -3647,7 +3665,6 @@ static struct mvpp2_bm_pool *
 mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                  int pkt_size)
 {
-       unsigned long flags = 0;
        struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool];
        int num;
 
@@ -3656,8 +3673,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                return NULL;
        }
 
-       spin_lock_irqsave(&new_pool->lock, flags);
-
        if (new_pool->type == MVPP2_BM_FREE)
                new_pool->type = type;
 
@@ -3686,8 +3701,6 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
                if (num != pkts_num) {
                        WARN(1, "pool %d: %d of %d allocated\n",
                             new_pool->id, num, pkts_num);
-                       /* We need to undo the bufs_add() allocations */
-                       spin_unlock_irqrestore(&new_pool->lock, flags);
                        return NULL;
                }
        }
@@ -3695,15 +3708,12 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
        mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
                                  MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
 
-       spin_unlock_irqrestore(&new_pool->lock, flags);
-
        return new_pool;
 }
 
 /* Initialize pools for swf */
 static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
 {
-       unsigned long flags = 0;
        int rxq;
 
        if (!port->pool_long) {
@@ -3714,9 +3724,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
                if (!port->pool_long)
                        return -ENOMEM;
 
-               spin_lock_irqsave(&port->pool_long->lock, flags);
                port->pool_long->port_map |= (1 << port->id);
-               spin_unlock_irqrestore(&port->pool_long->lock, flags);
 
                for (rxq = 0; rxq < rxq_number; rxq++)
                        mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id);
@@ -3730,9 +3738,7 @@ static int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
                if (!port->pool_short)
                        return -ENOMEM;
 
-               spin_lock_irqsave(&port->pool_short->lock, flags);
                port->pool_short->port_map |= (1 << port->id);
-               spin_unlock_irqrestore(&port->pool_short->lock, flags);
 
                for (rxq = 0; rxq < rxq_number; rxq++)
                        mvpp2_rxq_short_pool_set(port, rxq,
@@ -3806,7 +3812,6 @@ static void mvpp2_interrupts_unmask(void *arg)
 
        mvpp2_write(port->priv, MVPP2_ISR_RX_TX_MASK_REG(port->id),
                    (MVPP2_CAUSE_MISC_SUM_MASK |
-                    MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK |
                     MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK));
 }
 
@@ -4382,23 +4387,6 @@ static void mvpp2_rx_time_coal_set(struct mvpp2_port *port,
        rxq->time_coal = usec;
 }
 
-/* Set threshold for TX_DONE pkts coalescing */
-static void mvpp2_tx_done_pkts_coal_set(void *arg)
-{
-       struct mvpp2_port *port = arg;
-       int queue;
-       u32 val;
-
-       for (queue = 0; queue < txq_number; queue++) {
-               struct mvpp2_tx_queue *txq = port->txqs[queue];
-
-               val = (txq->done_pkts_coal << MVPP2_TRANSMITTED_THRESH_OFFSET) &
-                      MVPP2_TRANSMITTED_THRESH_MASK;
-               mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
-               mvpp2_write(port->priv, MVPP2_TXQ_THRESH_REG, val);
-       }
-}
-
 /* Free Tx queue skbuffs */
 static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
                                struct mvpp2_tx_queue *txq,
@@ -4407,8 +4395,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
        int i;
 
        for (i = 0; i < num; i++) {
-               struct mvpp2_tx_desc *tx_desc = txq->descs +
-                                                       txq_pcpu->txq_get_index;
+               dma_addr_t buf_phys_addr =
+                                   txq_pcpu->tx_buffs[txq_pcpu->txq_get_index];
                struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index];
 
                mvpp2_txq_inc_get(txq_pcpu);
@@ -4416,8 +4404,8 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
                if (!skb)
                        continue;
 
-               dma_unmap_single(port->dev->dev.parent, tx_desc->buf_phys_addr,
-                                tx_desc->data_size, DMA_TO_DEVICE);
+               dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
+                                skb_headlen(skb), DMA_TO_DEVICE);
                dev_kfree_skb_any(skb);
        }
 }
@@ -4433,7 +4421,7 @@ static inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port,
 static inline struct mvpp2_tx_queue *mvpp2_get_tx_queue(struct mvpp2_port *port,
                                                        u32 cause)
 {
-       int queue = fls(cause >> 16) - 1;
+       int queue = fls(cause) - 1;
 
        return port->txqs[queue];
 }
@@ -4460,6 +4448,29 @@ static void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
                        netif_tx_wake_queue(nq);
 }
 
+static unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause)
+{
+       struct mvpp2_tx_queue *txq;
+       struct mvpp2_txq_pcpu *txq_pcpu;
+       unsigned int tx_todo = 0;
+
+       while (cause) {
+               txq = mvpp2_get_tx_queue(port, cause);
+               if (!txq)
+                       break;
+
+               txq_pcpu = this_cpu_ptr(txq->pcpu);
+
+               if (txq_pcpu->count) {
+                       mvpp2_txq_done(port, txq, txq_pcpu);
+                       tx_todo += txq_pcpu->count;
+               }
+
+               cause &= ~(1 << txq->log_id);
+       }
+       return tx_todo;
+}
+
 /* Rx/Tx queue initialization/cleanup methods */
 
 /* Allocate and initialize descriptors for aggr TXQ */
@@ -4649,12 +4660,13 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
                txq_pcpu->tx_skb = kmalloc(txq_pcpu->size *
                                           sizeof(*txq_pcpu->tx_skb),
                                           GFP_KERNEL);
-               if (!txq_pcpu->tx_skb) {
-                       dma_free_coherent(port->dev->dev.parent,
-                                         txq->size * MVPP2_DESC_ALIGNED_SIZE,
-                                         txq->descs, txq->descs_phys);
-                       return -ENOMEM;
-               }
+               if (!txq_pcpu->tx_skb)
+                       goto error;
+
+               txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size *
+                                            sizeof(dma_addr_t), GFP_KERNEL);
+               if (!txq_pcpu->tx_buffs)
+                       goto error;
 
                txq_pcpu->count = 0;
                txq_pcpu->reserved_num = 0;
@@ -4663,6 +4675,19 @@ static int mvpp2_txq_init(struct mvpp2_port *port,
        }
 
        return 0;
+
+error:
+       for_each_present_cpu(cpu) {
+               txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
+               kfree(txq_pcpu->tx_skb);
+               kfree(txq_pcpu->tx_buffs);
+       }
+
+       dma_free_coherent(port->dev->dev.parent,
+                         txq->size * MVPP2_DESC_ALIGNED_SIZE,
+                         txq->descs, txq->descs_phys);
+
+       return -ENOMEM;
 }
 
 /* Free allocated TXQ resources */
@@ -4675,6 +4700,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port,
        for_each_present_cpu(cpu) {
                txq_pcpu = per_cpu_ptr(txq->pcpu, cpu);
                kfree(txq_pcpu->tx_skb);
+               kfree(txq_pcpu->tx_buffs);
        }
 
        if (txq->descs)
@@ -4805,7 +4831,6 @@ static int mvpp2_setup_txqs(struct mvpp2_port *port)
                        goto err_cleanup;
        }
 
-       on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1);
        on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1);
        return 0;
 
@@ -4887,6 +4912,49 @@ static void mvpp2_link_event(struct net_device *dev)
        }
 }
 
+static void mvpp2_timer_set(struct mvpp2_port_pcpu *port_pcpu)
+{
+       ktime_t interval;
+
+       if (!port_pcpu->timer_scheduled) {
+               port_pcpu->timer_scheduled = true;
+               interval = ktime_set(0, MVPP2_TXDONE_HRTIMER_PERIOD_NS);
+               hrtimer_start(&port_pcpu->tx_done_timer, interval,
+                             HRTIMER_MODE_REL_PINNED);
+       }
+}
+
+static void mvpp2_tx_proc_cb(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct mvpp2_port *port = netdev_priv(dev);
+       struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+       unsigned int tx_todo, cause;
+
+       if (!netif_running(dev))
+               return;
+       port_pcpu->timer_scheduled = false;
+
+       /* Process all the Tx queues */
+       cause = (1 << txq_number) - 1;
+       tx_todo = mvpp2_tx_done(port, cause);
+
+       /* Set the timer in case not all the packets were processed */
+       if (tx_todo)
+               mvpp2_timer_set(port_pcpu);
+}
+
+static enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer)
+{
+       struct mvpp2_port_pcpu *port_pcpu = container_of(timer,
+                                                        struct mvpp2_port_pcpu,
+                                                        tx_done_timer);
+
+       tasklet_schedule(&port_pcpu->tx_done_tasklet);
+
+       return HRTIMER_NORESTART;
+}
+
 /* Main RX/TX processing routines */
 
 /* Display more error info */
@@ -5144,11 +5212,11 @@ static int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
                if (i == (skb_shinfo(skb)->nr_frags - 1)) {
                        /* Last descriptor */
                        tx_desc->command = MVPP2_TXD_L_DESC;
-                       mvpp2_txq_inc_put(txq_pcpu, skb);
+                       mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
                } else {
                        /* Descriptor in the middle: Not First, Not Last */
                        tx_desc->command = 0;
-                       mvpp2_txq_inc_put(txq_pcpu, NULL);
+                       mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
                }
        }
 
@@ -5214,12 +5282,12 @@ static int mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
                /* First and Last descriptor */
                tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
                tx_desc->command = tx_cmd;
-               mvpp2_txq_inc_put(txq_pcpu, skb);
+               mvpp2_txq_inc_put(txq_pcpu, skb, tx_desc);
        } else {
                /* First but not Last */
                tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE;
                tx_desc->command = tx_cmd;
-               mvpp2_txq_inc_put(txq_pcpu, NULL);
+               mvpp2_txq_inc_put(txq_pcpu, NULL, tx_desc);
 
                /* Continue with other skb fragments */
                if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
@@ -5255,6 +5323,17 @@ out:
                dev_kfree_skb_any(skb);
        }
 
+       /* Finalize TX processing */
+       if (txq_pcpu->count >= txq->done_pkts_coal)
+               mvpp2_txq_done(port, txq, txq_pcpu);
+
+       /* Set the timer in case not all frags were processed */
+       if (txq_pcpu->count <= frags && txq_pcpu->count > 0) {
+               struct mvpp2_port_pcpu *port_pcpu = this_cpu_ptr(port->pcpu);
+
+               mvpp2_timer_set(port_pcpu);
+       }
+
        return NETDEV_TX_OK;
 }
 
@@ -5268,10 +5347,11 @@ static inline void mvpp2_cause_error(struct net_device *dev, int cause)
                netdev_err(dev, "tx fifo underrun error\n");
 }
 
-static void mvpp2_txq_done_percpu(void *arg)
+static int mvpp2_poll(struct napi_struct *napi, int budget)
 {
-       struct mvpp2_port *port = arg;
-       u32 cause_rx_tx, cause_tx, cause_misc;
+       u32 cause_rx_tx, cause_rx, cause_misc;
+       int rx_done = 0;
+       struct mvpp2_port *port = netdev_priv(napi->dev);
 
        /* Rx/Tx cause register
         *
@@ -5285,7 +5365,7 @@ static void mvpp2_txq_done_percpu(void *arg)
         */
        cause_rx_tx = mvpp2_read(port->priv,
                                 MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
-       cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
+       cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
        cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
 
        if (cause_misc) {
@@ -5297,26 +5377,6 @@ static void mvpp2_txq_done_percpu(void *arg)
                            cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK);
        }
 
-       /* Release TX descriptors */
-       if (cause_tx) {
-               struct mvpp2_tx_queue *txq = mvpp2_get_tx_queue(port, cause_tx);
-               struct mvpp2_txq_pcpu *txq_pcpu = this_cpu_ptr(txq->pcpu);
-
-               if (txq_pcpu->count)
-                       mvpp2_txq_done(port, txq, txq_pcpu);
-       }
-}
-
-static int mvpp2_poll(struct napi_struct *napi, int budget)
-{
-       u32 cause_rx_tx, cause_rx;
-       int rx_done = 0;
-       struct mvpp2_port *port = netdev_priv(napi->dev);
-
-       on_each_cpu(mvpp2_txq_done_percpu, port, 1);
-
-       cause_rx_tx = mvpp2_read(port->priv,
-                                MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
        cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
 
        /* Process RX packets */
@@ -5561,6 +5621,8 @@ err_cleanup_rxqs:
 static int mvpp2_stop(struct net_device *dev)
 {
        struct mvpp2_port *port = netdev_priv(dev);
+       struct mvpp2_port_pcpu *port_pcpu;
+       int cpu;
 
        mvpp2_stop_dev(port);
        mvpp2_phy_disconnect(port);
@@ -5569,6 +5631,13 @@ static int mvpp2_stop(struct net_device *dev)
        on_each_cpu(mvpp2_interrupts_mask, port, 1);
 
        free_irq(port->irq, port);
+       for_each_present_cpu(cpu) {
+               port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+               hrtimer_cancel(&port_pcpu->tx_done_timer);
+               port_pcpu->timer_scheduled = false;
+               tasklet_kill(&port_pcpu->tx_done_tasklet);
+       }
        mvpp2_cleanup_rxqs(port);
        mvpp2_cleanup_txqs(port);
 
@@ -5784,7 +5853,6 @@ static int mvpp2_ethtool_set_coalesce(struct net_device *dev,
                txq->done_pkts_coal = c->tx_max_coalesced_frames;
        }
 
-       on_each_cpu(mvpp2_tx_done_pkts_coal_set, port, 1);
        return 0;
 }
 
@@ -6035,6 +6103,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
 {
        struct device_node *phy_node;
        struct mvpp2_port *port;
+       struct mvpp2_port_pcpu *port_pcpu;
        struct net_device *dev;
        struct resource *res;
        const char *dt_mac_addr;
@@ -6044,7 +6113,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        int features;
        int phy_mode;
        int priv_common_regs_num = 2;
-       int err, i;
+       int err, i, cpu;
 
        dev = alloc_etherdev_mqs(sizeof(struct mvpp2_port), txq_number,
                                 rxq_number);
@@ -6135,6 +6204,24 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        }
        mvpp2_port_power_up(port);
 
+       port->pcpu = alloc_percpu(struct mvpp2_port_pcpu);
+       if (!port->pcpu) {
+               err = -ENOMEM;
+               goto err_free_txq_pcpu;
+       }
+
+       for_each_present_cpu(cpu) {
+               port_pcpu = per_cpu_ptr(port->pcpu, cpu);
+
+               hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
+                            HRTIMER_MODE_REL_PINNED);
+               port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
+               port_pcpu->timer_scheduled = false;
+
+               tasklet_init(&port_pcpu->tx_done_tasklet, mvpp2_tx_proc_cb,
+                            (unsigned long)dev);
+       }
+
        netif_napi_add(dev, &port->napi, mvpp2_poll, NAPI_POLL_WEIGHT);
        features = NETIF_F_SG | NETIF_F_IP_CSUM;
        dev->features = features | NETIF_F_RXCSUM;
@@ -6144,7 +6231,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        err = register_netdev(dev);
        if (err < 0) {
                dev_err(&pdev->dev, "failed to register netdev\n");
-               goto err_free_txq_pcpu;
+               goto err_free_port_pcpu;
        }
        netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
 
@@ -6153,6 +6240,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        priv->port_list[id] = port;
        return 0;
 
+err_free_port_pcpu:
+       free_percpu(port->pcpu);
 err_free_txq_pcpu:
        for (i = 0; i < txq_number; i++)
                free_percpu(port->txqs[i]->pcpu);
@@ -6171,6 +6260,7 @@ static void mvpp2_port_remove(struct mvpp2_port *port)
        int i;
 
        unregister_netdev(port->dev);
+       free_percpu(port->pcpu);
        free_percpu(port->stats);
        for (i = 0; i < txq_number; i++)
                free_percpu(port->txqs[i]->pcpu);
index 82040137d7d9723a0ab027fe72bc25a3063368b3..0a3202047569c707a28f62376466e72fdcd8cd00 100644 (file)
@@ -686,6 +686,7 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
 {
        struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
        struct mlx4_cmd_context *context;
+       long ret_wait;
        int err = 0;
 
        down(&cmd->event_sem);
@@ -711,8 +712,20 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
        if (err)
                goto out_reset;
 
-       if (!wait_for_completion_timeout(&context->done,
-                                        msecs_to_jiffies(timeout))) {
+       if (op == MLX4_CMD_SENSE_PORT) {
+               ret_wait =
+                       wait_for_completion_interruptible_timeout(&context->done,
+                                                                 msecs_to_jiffies(timeout));
+               if (ret_wait < 0) {
+                       context->fw_status = 0;
+                       context->out_param = 0;
+                       context->result = 0;
+               }
+       } else {
+               ret_wait = (long)wait_for_completion_timeout(&context->done,
+                                                            msecs_to_jiffies(timeout));
+       }
+       if (!ret_wait) {
                mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
                          op);
                if (op == MLX4_CMD_NOP) {
index 7a4f20bb7fcb4c2640ad8111f5a98ff95088075c..9c145dddd7175fffda22c71a8f31d4d27d807ceb 100644 (file)
@@ -246,7 +246,6 @@ static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv,
 
 static inline bool mlx4_en_is_ring_empty(struct mlx4_en_rx_ring *ring)
 {
-       BUG_ON((u32)(ring->prod - ring->cons) > ring->actual_size);
        return ring->prod == ring->cons;
 }
 
index aae13adfb492b885bcf2fba03b042b949c3f5575..8e81e53c370e7d54e6367c012212cccc73ee26fd 100644 (file)
@@ -601,7 +601,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                                        continue;
                                                mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN to slave: %d, port:%d\n",
                                                         __func__, i, port);
-                                               s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
+                                               s_info = &priv->mfunc.master.vf_oper[i].vport[port].state;
                                                if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
                                                        eqe->event.port_change.port =
                                                                cpu_to_be32(
@@ -640,7 +640,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                                        continue;
                                                if (i == mlx4_master_func_num(dev))
                                                        continue;
-                                               s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
+                                               s_info = &priv->mfunc.master.vf_oper[i].vport[port].state;
                                                if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
                                                        eqe->event.port_change.port =
                                                                cpu_to_be32(
index 12fbfcb44d8acdedf08fef880a12e53145f8836e..29c2a017a450277657a5d5e9ad4a4878575cbb2c 100644 (file)
@@ -2273,6 +2273,11 @@ static int mlx4_allocate_default_counters(struct mlx4_dev *dev)
                } else if (err == -ENOENT) {
                        err = 0;
                        continue;
+               } else if (mlx4_is_slave(dev) && err == -EINVAL) {
+                       priv->def_counter[port] = MLX4_SINK_COUNTER_INDEX(dev);
+                       mlx4_warn(dev, "can't allocate counter from old PF driver, using index %d\n",
+                                 MLX4_SINK_COUNTER_INDEX(dev));
+                       err = 0;
                } else {
                        mlx4_err(dev, "%s: failed to allocate default counter port %d err %d\n",
                                 __func__, port + 1, err);
index afad529838de748efc9f9253c6fde42abbe954a3..06e3e1e54c35d6078321d792d1e0e537ec95a207 100644 (file)
@@ -391,6 +391,8 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
        /* disable cmdif checksum */
        MLX5_SET(cmd_hca_cap, set_hca_cap, cmdif_checksum, 0);
 
+       MLX5_SET(cmd_hca_cap, set_hca_cap, log_uar_page_sz, PAGE_SHIFT - 12);
+
        err = set_caps(dev, set_ctx, set_sz);
 
 query_ex:
index f78909a00f150edfd76065b2b993d9660edaebdd..09d2e16fd6b00bfdd0c20fc10c64abd03c29a935 100644 (file)
@@ -952,9 +952,8 @@ static int ks8842_alloc_dma_bufs(struct net_device *netdev)
 
        sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
                tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
-       err = dma_mapping_error(adapter->dev,
-               sg_dma_address(&tx_ctl->sg));
-       if (err) {
+       if (dma_mapping_error(adapter->dev, sg_dma_address(&tx_ctl->sg))) {
+               err = -ENOMEM;
                sg_dma_address(&tx_ctl->sg) = 0;
                goto err;
        }
index 33669c29b341cb42bb106ec2c634663d0adb2415..753ea8bad953c3a75487e3a544cc4106d4a46f68 100644 (file)
@@ -1415,7 +1415,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
        if (fw->size & 0xF) {
                addr = dest + size;
                for (i = 0; i < (fw->size & 0xF); i++)
-                       data[i] = temp[size + i];
+                       data[i] = ((u8 *)temp)[size + i];
                for (; i < 16; i++)
                        data[i] = 0;
                ret = qlcnic_ms_mem_write128(adapter, addr,
index 3df51faf18ae3ba8ce6bb7f49e6f51e4da1be738..f790f61ea78a2b4f1008da82eca29132ff5bdcc0 100644 (file)
@@ -4875,10 +4875,12 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_46:
        case RTL_GIGA_MAC_VER_47:
        case RTL_GIGA_MAC_VER_48:
+               RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+               break;
        case RTL_GIGA_MAC_VER_49:
        case RTL_GIGA_MAC_VER_50:
        case RTL_GIGA_MAC_VER_51:
-               RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+               RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
                break;
        default:
                RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
index fd9745714d903fa5945956709491be934ea02c67..78849dd4ef8e9463c2420c84cc583a927492df58 100644 (file)
@@ -228,9 +228,7 @@ static void ravb_ring_format(struct net_device *ndev, int q)
        struct ravb_desc *desc = NULL;
        int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q];
        int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q];
-       struct sk_buff *skb;
        dma_addr_t dma_addr;
-       void *buffer;
        int i;
 
        priv->cur_rx[q] = 0;
@@ -241,41 +239,28 @@ static void ravb_ring_format(struct net_device *ndev, int q)
        memset(priv->rx_ring[q], 0, rx_ring_size);
        /* Build RX ring buffer */
        for (i = 0; i < priv->num_rx_ring[q]; i++) {
-               priv->rx_skb[q][i] = NULL;
-               skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
-               if (!skb)
-                       break;
-               ravb_set_buffer_align(skb);
                /* RX descriptor */
                rx_desc = &priv->rx_ring[q][i];
                /* The size of the buffer should be on 16-byte boundary. */
                rx_desc->ds_cc = cpu_to_le16(ALIGN(PKT_BUF_SZ, 16));
-               dma_addr = dma_map_single(&ndev->dev, skb->data,
+               dma_addr = dma_map_single(&ndev->dev, priv->rx_skb[q][i]->data,
                                          ALIGN(PKT_BUF_SZ, 16),
                                          DMA_FROM_DEVICE);
-               if (dma_mapping_error(&ndev->dev, dma_addr)) {
-                       dev_kfree_skb(skb);
-                       break;
-               }
-               priv->rx_skb[q][i] = skb;
+               /* We just set the data size to 0 for a failed mapping which
+                * should prevent DMA from happening...
+                */
+               if (dma_mapping_error(&ndev->dev, dma_addr))
+                       rx_desc->ds_cc = cpu_to_le16(0);
                rx_desc->dptr = cpu_to_le32(dma_addr);
                rx_desc->die_dt = DT_FEMPTY;
        }
        rx_desc = &priv->rx_ring[q][i];
        rx_desc->dptr = cpu_to_le32((u32)priv->rx_desc_dma[q]);
        rx_desc->die_dt = DT_LINKFIX; /* type */
-       priv->dirty_rx[q] = (u32)(i - priv->num_rx_ring[q]);
 
        memset(priv->tx_ring[q], 0, tx_ring_size);
        /* Build TX ring buffer */
        for (i = 0; i < priv->num_tx_ring[q]; i++) {
-               priv->tx_skb[q][i] = NULL;
-               priv->tx_buffers[q][i] = NULL;
-               buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL);
-               if (!buffer)
-                       break;
-               /* Aligned TX buffer */
-               priv->tx_buffers[q][i] = buffer;
                tx_desc = &priv->tx_ring[q][i];
                tx_desc->die_dt = DT_EEMPTY;
        }
@@ -298,7 +283,10 @@ static void ravb_ring_format(struct net_device *ndev, int q)
 static int ravb_ring_init(struct net_device *ndev, int q)
 {
        struct ravb_private *priv = netdev_priv(ndev);
+       struct sk_buff *skb;
        int ring_size;
+       void *buffer;
+       int i;
 
        /* Allocate RX and TX skb rings */
        priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q],
@@ -308,12 +296,28 @@ static int ravb_ring_init(struct net_device *ndev, int q)
        if (!priv->rx_skb[q] || !priv->tx_skb[q])
                goto error;
 
+       for (i = 0; i < priv->num_rx_ring[q]; i++) {
+               skb = netdev_alloc_skb(ndev, PKT_BUF_SZ + RAVB_ALIGN - 1);
+               if (!skb)
+                       goto error;
+               ravb_set_buffer_align(skb);
+               priv->rx_skb[q][i] = skb;
+       }
+
        /* Allocate rings for the aligned buffers */
        priv->tx_buffers[q] = kcalloc(priv->num_tx_ring[q],
                                      sizeof(*priv->tx_buffers[q]), GFP_KERNEL);
        if (!priv->tx_buffers[q])
                goto error;
 
+       for (i = 0; i < priv->num_tx_ring[q]; i++) {
+               buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL);
+               if (!buffer)
+                       goto error;
+               /* Aligned TX buffer */
+               priv->tx_buffers[q][i] = buffer;
+       }
+
        /* Allocate all RX descriptors. */
        ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1);
        priv->rx_ring[q] = dma_alloc_coherent(NULL, ring_size,
@@ -524,6 +528,10 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
                if (--boguscnt < 0)
                        break;
 
+               /* We use 0-byte descriptors to mark the DMA mapping errors */
+               if (!pkt_len)
+                       continue;
+
                if (desc_status & MSC_MC)
                        stats->multicast++;
 
@@ -543,10 +551,9 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
 
                        skb = priv->rx_skb[q][entry];
                        priv->rx_skb[q][entry] = NULL;
-                       dma_sync_single_for_cpu(&ndev->dev,
-                                               le32_to_cpu(desc->dptr),
-                                               ALIGN(PKT_BUF_SZ, 16),
-                                               DMA_FROM_DEVICE);
+                       dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
+                                        ALIGN(PKT_BUF_SZ, 16),
+                                        DMA_FROM_DEVICE);
                        get_ts &= (q == RAVB_NC) ?
                                        RAVB_RXTSTAMP_TYPE_V2_L2_EVENT :
                                        ~RAVB_RXTSTAMP_TYPE_V2_L2_EVENT;
@@ -584,17 +591,15 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q)
                        if (!skb)
                                break;  /* Better luck next round. */
                        ravb_set_buffer_align(skb);
-                       dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr),
-                                        ALIGN(PKT_BUF_SZ, 16),
-                                        DMA_FROM_DEVICE);
                        dma_addr = dma_map_single(&ndev->dev, skb->data,
                                                  le16_to_cpu(desc->ds_cc),
                                                  DMA_FROM_DEVICE);
                        skb_checksum_none_assert(skb);
-                       if (dma_mapping_error(&ndev->dev, dma_addr)) {
-                               dev_kfree_skb_any(skb);
-                               break;
-                       }
+                       /* We just set the data size to 0 for a failed mapping
+                        * which should prevent DMA  from happening...
+                        */
+                       if (dma_mapping_error(&ndev->dev, dma_addr))
+                               desc->ds_cc = cpu_to_le16(0);
                        desc->dptr = cpu_to_le32(dma_addr);
                        priv->rx_skb[q][entry] = skb;
                }
@@ -1279,7 +1284,6 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        u32 dma_addr;
        void *buffer;
        u32 entry;
-       u32 tccr;
 
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q]) {
@@ -1328,9 +1332,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        dma_wmb();
        desc->die_dt = DT_FSINGLE;
 
-       tccr = ravb_read(ndev, TCCR);
-       if (!(tccr & (TCCR_TSRQ0 << q)))
-               ravb_write(ndev, tccr | (TCCR_TSRQ0 << q), TCCR);
+       ravb_write(ndev, ravb_read(ndev, TCCR) | (TCCR_TSRQ0 << q), TCCR);
 
        priv->cur_tx[q]++;
        if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q] &&
index 2d8578cade03790782af7e97a1f59f9848301ae6..2e7f9a2834be320eef4a7bed44d8c787f72f3e65 100644 (file)
@@ -4821,6 +4821,7 @@ static void rocker_remove_ports(const struct rocker *rocker)
                rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE,
                                   ROCKER_OP_FLAG_REMOVE);
                unregister_netdev(rocker_port->dev);
+               free_netdev(rocker_port->dev);
        }
        kfree(rocker->ports);
 }
index 84764345546829a02bd1cf8650d16544c5fe968e..605cc8948594626783e093db71d474d638a26bc1 100644 (file)
@@ -101,6 +101,11 @@ static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx)
        return resource_size(&efx->pci_dev->resource[bar]);
 }
 
+static bool efx_ef10_is_vf(struct efx_nic *efx)
+{
+       return efx->type->is_vf;
+}
+
 static int efx_ef10_get_pf_index(struct efx_nic *efx)
 {
        MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
@@ -677,6 +682,48 @@ static int efx_ef10_probe_pf(struct efx_nic *efx)
        return efx_ef10_probe(efx);
 }
 
+int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN);
+
+       MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
+       return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf),
+                           NULL, 0, NULL);
+}
+
+int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN);
+
+       MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
+       return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf),
+                           NULL, 0, NULL);
+}
+
+int efx_ef10_vport_add_mac(struct efx_nic *efx,
+                          unsigned int port_id, u8 *mac)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN);
+
+       MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id);
+       ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac);
+
+       return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf,
+                           sizeof(inbuf), NULL, 0, NULL);
+}
+
+int efx_ef10_vport_del_mac(struct efx_nic *efx,
+                          unsigned int port_id, u8 *mac)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
+
+       MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
+       ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
+
+       return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
+                           sizeof(inbuf), NULL, 0, NULL);
+}
+
 #ifdef CONFIG_SFC_SRIOV
 static int efx_ef10_probe_vf(struct efx_nic *efx)
 {
@@ -3804,6 +3851,72 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
        WARN_ON(remove_failed);
 }
 
+static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
+{
+       struct efx_ef10_nic_data *nic_data = efx->nic_data;
+       u8 mac_old[ETH_ALEN];
+       int rc, rc2;
+
+       /* Only reconfigure a PF-created vport */
+       if (is_zero_ether_addr(nic_data->vport_mac))
+               return 0;
+
+       efx_device_detach_sync(efx);
+       efx_net_stop(efx->net_dev);
+       down_write(&efx->filter_sem);
+       efx_ef10_filter_table_remove(efx);
+       up_write(&efx->filter_sem);
+
+       rc = efx_ef10_vadaptor_free(efx, nic_data->vport_id);
+       if (rc)
+               goto restore_filters;
+
+       ether_addr_copy(mac_old, nic_data->vport_mac);
+       rc = efx_ef10_vport_del_mac(efx, nic_data->vport_id,
+                                   nic_data->vport_mac);
+       if (rc)
+               goto restore_vadaptor;
+
+       rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id,
+                                   efx->net_dev->dev_addr);
+       if (!rc) {
+               ether_addr_copy(nic_data->vport_mac, efx->net_dev->dev_addr);
+       } else {
+               rc2 = efx_ef10_vport_add_mac(efx, nic_data->vport_id, mac_old);
+               if (rc2) {
+                       /* Failed to add original MAC, so clear vport_mac */
+                       eth_zero_addr(nic_data->vport_mac);
+                       goto reset_nic;
+               }
+       }
+
+restore_vadaptor:
+       rc2 = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id);
+       if (rc2)
+               goto reset_nic;
+restore_filters:
+       down_write(&efx->filter_sem);
+       rc2 = efx_ef10_filter_table_probe(efx);
+       up_write(&efx->filter_sem);
+       if (rc2)
+               goto reset_nic;
+
+       rc2 = efx_net_open(efx->net_dev);
+       if (rc2)
+               goto reset_nic;
+
+       netif_device_attach(efx->net_dev);
+
+       return rc;
+
+reset_nic:
+       netif_err(efx, drv, efx->net_dev,
+                 "Failed to restore when changing MAC address - scheduling reset\n");
+       efx_schedule_reset(efx, RESET_TYPE_DATAPATH);
+
+       return rc ? rc : rc2;
+}
+
 static int efx_ef10_set_mac_address(struct efx_nic *efx)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN);
@@ -3820,8 +3933,8 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
                        efx->net_dev->dev_addr);
        MCDI_SET_DWORD(inbuf, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID,
                       nic_data->vport_id);
-       rc = efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf,
-                         sizeof(inbuf), NULL, 0, NULL);
+       rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VADAPTOR_SET_MAC, inbuf,
+                               sizeof(inbuf), NULL, 0, NULL);
 
        efx_ef10_filter_table_probe(efx);
        up_write(&efx->filter_sem);
@@ -3829,38 +3942,27 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
                efx_net_open(efx->net_dev);
        netif_device_attach(efx->net_dev);
 
-#if !defined(CONFIG_SFC_SRIOV)
-       if (rc == -EPERM)
-               netif_err(efx, drv, efx->net_dev,
-                         "Cannot change MAC address; use sfboot to enable mac-spoofing"
-                         " on this interface\n");
-#else
-       if (rc == -EPERM) {
+#ifdef CONFIG_SFC_SRIOV
+       if (efx->pci_dev->is_virtfn && efx->pci_dev->physfn) {
                struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
 
-               /* Switch to PF and change MAC address on vport */
-               if (efx->pci_dev->is_virtfn && pci_dev_pf) {
-                       struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
+               if (rc == -EPERM) {
+                       struct efx_nic *efx_pf;
 
-                       if (!efx_ef10_sriov_set_vf_mac(efx_pf,
-                                                      nic_data->vf_index,
-                                                      efx->net_dev->dev_addr))
-                               return 0;
-               }
-               netif_err(efx, drv, efx->net_dev,
-                         "Cannot change MAC address; use sfboot to enable mac-spoofing"
-                         " on this interface\n");
-       } else if (efx->pci_dev->is_virtfn) {
-               /* Successfully changed by VF (with MAC spoofing), so update the
-                * parent PF if possible.
-                */
-               struct pci_dev *pci_dev_pf = efx->pci_dev->physfn;
+                       /* Switch to PF and change MAC address on vport */
+                       efx_pf = pci_get_drvdata(pci_dev_pf);
 
-               if (pci_dev_pf) {
+                       rc = efx_ef10_sriov_set_vf_mac(efx_pf,
+                                                      nic_data->vf_index,
+                                                      efx->net_dev->dev_addr);
+               } else if (!rc) {
                        struct efx_nic *efx_pf = pci_get_drvdata(pci_dev_pf);
                        struct efx_ef10_nic_data *nic_data = efx_pf->nic_data;
                        unsigned int i;
 
+                       /* MAC address successfully changed by VF (with MAC
+                        * spoofing) so update the parent PF if possible.
+                        */
                        for (i = 0; i < efx_pf->vf_count; ++i) {
                                struct ef10_vf *vf = nic_data->vf + i;
 
@@ -3871,8 +3973,24 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
                                }
                        }
                }
-       }
+       } else
 #endif
+       if (rc == -EPERM) {
+               netif_err(efx, drv, efx->net_dev,
+                         "Cannot change MAC address; use sfboot to enable"
+                         " mac-spoofing on this interface\n");
+       } else if (rc == -ENOSYS && !efx_ef10_is_vf(efx)) {
+               /* If the active MCFW does not support MC_CMD_VADAPTOR_SET_MAC
+                * fall-back to the method of changing the MAC address on the
+                * vport.  This only applies to PFs because such versions of
+                * MCFW do not support VFs.
+                */
+               rc = efx_ef10_vport_set_mac_address(efx);
+       } else {
+               efx_mcdi_display_error(efx, MC_CMD_VADAPTOR_SET_MAC,
+                                      sizeof(inbuf), NULL, 0, rc);
+       }
+
        return rc;
 }
 
index 6c9b6e45509a18706ef9488e097f83f9f4a41ecf..3c17f274e80200ca8bb08b5a0db62aa34a943af9 100644 (file)
@@ -29,30 +29,6 @@ static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id,
                            NULL, 0, NULL);
 }
 
-static int efx_ef10_vport_add_mac(struct efx_nic *efx,
-                                 unsigned int port_id, u8 *mac)
-{
-       MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN);
-
-       MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id);
-       ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac);
-
-       return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf,
-                           sizeof(inbuf), NULL, 0, NULL);
-}
-
-static int efx_ef10_vport_del_mac(struct efx_nic *efx,
-                                 unsigned int port_id, u8 *mac)
-{
-       MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
-
-       MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
-       ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
-
-       return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
-                           sizeof(inbuf), NULL, 0, NULL);
-}
-
 static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id,
                                  unsigned int vswitch_type)
 {
@@ -136,24 +112,6 @@ static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id)
                            NULL, 0, NULL);
 }
 
-static int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id)
-{
-       MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_ALLOC_IN_LEN);
-
-       MCDI_SET_DWORD(inbuf, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
-       return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_ALLOC, inbuf, sizeof(inbuf),
-                           NULL, 0, NULL);
-}
-
-static int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id)
-{
-       MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_FREE_IN_LEN);
-
-       MCDI_SET_DWORD(inbuf, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id);
-       return efx_mcdi_rpc(efx, MC_CMD_VADAPTOR_FREE, inbuf, sizeof(inbuf),
-                           NULL, 0, NULL);
-}
-
 static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
 {
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
@@ -640,21 +598,21 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
                                  MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
                                  vf->vlan, &vf->vport_id);
        if (rc)
-               goto reset_nic;
+               goto reset_nic_up_write;
 
 restore_mac:
        if (!is_zero_ether_addr(vf->mac)) {
                rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
                if (rc2) {
                        eth_zero_addr(vf->mac);
-                       goto reset_nic;
+                       goto reset_nic_up_write;
                }
        }
 
 restore_evb_port:
        rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
        if (rc2)
-               goto reset_nic;
+               goto reset_nic_up_write;
        else
                vf->vport_assigned = 1;
 
@@ -662,14 +620,16 @@ restore_vadaptor:
        if (vf->efx) {
                rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
                if (rc2)
-                       goto reset_nic;
+                       goto reset_nic_up_write;
        }
 
 restore_filters:
        if (vf->efx) {
                rc2 = vf->efx->type->filter_table_probe(vf->efx);
                if (rc2)
-                       goto reset_nic;
+                       goto reset_nic_up_write;
+
+               up_write(&vf->efx->filter_sem);
 
                up_write(&vf->efx->filter_sem);
 
@@ -681,9 +641,12 @@ restore_filters:
        }
        return rc;
 
+reset_nic_up_write:
+       if (vf->efx)
+               up_write(&vf->efx->filter_sem);
+
 reset_nic:
        if (vf->efx) {
-               up_write(&vf->efx->filter_sem);
                netif_err(efx, drv, efx->net_dev,
                          "Failed to restore VF - scheduling reset.\n");
                efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH);
index db4ef537c6106c2627eaec7f9a9a6a45043ad4ef..6d25b92cb45e9ed1884ef806998db9523ebb452a 100644 (file)
@@ -65,5 +65,11 @@ int efx_ef10_vswitching_restore_pf(struct efx_nic *efx);
 int efx_ef10_vswitching_restore_vf(struct efx_nic *efx);
 void efx_ef10_vswitching_remove_pf(struct efx_nic *efx);
 void efx_ef10_vswitching_remove_vf(struct efx_nic *efx);
+int efx_ef10_vport_add_mac(struct efx_nic *efx,
+                          unsigned int port_id, u8 *mac);
+int efx_ef10_vport_del_mac(struct efx_nic *efx,
+                          unsigned int port_id, u8 *mac);
+int efx_ef10_vadaptor_alloc(struct efx_nic *efx, unsigned int port_id);
+int efx_ef10_vadaptor_free(struct efx_nic *efx, unsigned int port_id);
 
 #endif /* EF10_SRIOV_H */
index 804b9ad553d3841b076d4f3e8ee6ba627396226f..03bc03b67f08b3224f6e0d13b1fc0c189780c1af 100644 (file)
@@ -245,11 +245,17 @@ static int efx_check_disabled(struct efx_nic *efx)
  */
 static int efx_process_channel(struct efx_channel *channel, int budget)
 {
+       struct efx_tx_queue *tx_queue;
        int spent;
 
        if (unlikely(!channel->enabled))
                return 0;
 
+       efx_for_each_channel_tx_queue(tx_queue, channel) {
+               tx_queue->pkts_compl = 0;
+               tx_queue->bytes_compl = 0;
+       }
+
        spent = efx_nic_process_eventq(channel, budget);
        if (spent && efx_channel_has_rx_queue(channel)) {
                struct efx_rx_queue *rx_queue =
@@ -259,6 +265,14 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
                efx_fast_push_rx_descriptors(rx_queue, true);
        }
 
+       /* Update BQL */
+       efx_for_each_channel_tx_queue(tx_queue, channel) {
+               if (tx_queue->bytes_compl) {
+                       netdev_tx_completed_queue(tx_queue->core_txq,
+                               tx_queue->pkts_compl, tx_queue->bytes_compl);
+               }
+       }
+
        return spent;
 }
 
index d72f522bf9c3b2c0d9df322a7798ec1be6a1aba8..47d1e3a96522668a1cf1c80cacd141d2afbf1193 100644 (file)
@@ -241,6 +241,8 @@ struct efx_tx_queue {
        unsigned int read_count ____cacheline_aligned_in_smp;
        unsigned int old_write_count;
        unsigned int merge_events;
+       unsigned int bytes_compl;
+       unsigned int pkts_compl;
 
        /* Members used only on the xmit path */
        unsigned int insert_count ____cacheline_aligned_in_smp;
index aaf2987512b5db7472bdef518c4aa4c510612ef7..1833a01465711d56d1b2e09b03090792929d3a1b 100644 (file)
@@ -617,7 +617,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
        EFX_BUG_ON_PARANOID(index > tx_queue->ptr_mask);
 
        efx_dequeue_buffers(tx_queue, index, &pkts_compl, &bytes_compl);
-       netdev_tx_completed_queue(tx_queue->core_txq, pkts_compl, bytes_compl);
+       tx_queue->pkts_compl += pkts_compl;
+       tx_queue->bytes_compl += bytes_compl;
 
        if (pkts_compl > 1)
                ++tx_queue->merge_events;
index 7e3129e7f143a9990c89780a8e6638f8182e4892..f0e4bb4e3ec59f9695957dee9dec55a02d450da8 100644 (file)
@@ -42,7 +42,7 @@
 #define NSS_COMMON_CLK_DIV_MASK                        0x7f
 
 #define NSS_COMMON_CLK_SRC_CTRL                        0x14
-#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x)      (1 << x)
+#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x)      (x)
 /* Mode is coded on 1 bit but is different depending on the MAC ID:
  * MAC0: QSGMII=0 RGMII=1
  * MAC1: QSGMII=0 SGMII=0 RGMII=1
@@ -291,7 +291,7 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev)
 
        /* Configure the clock src according to the mode */
        regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
-       val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
+       val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
        switch (gmac->phy_mode) {
        case PHY_INTERFACE_MODE_RGMII:
                val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
index 50f7a7a26821c7a40cb73294a4844406ea9caee5..864b476f7fd5a33b81ac2f6ea9b08e0cf99d299d 100644 (file)
@@ -2843,7 +2843,7 @@ int stmmac_dvr_probe(struct device *device,
        if (res->mac)
                memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
 
-       dev_set_drvdata(device, priv);
+       dev_set_drvdata(device, priv->dev);
 
        /* Verify driver arguments */
        stmmac_verify_args();
index f3918c7e7eeb373a6736bb5145c33320acbabc53..bcdc8955c71945cf62e2d62e138d17a16f937949 100644 (file)
@@ -413,3 +413,7 @@ static int stmmac_pltfr_resume(struct device *dev)
 SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
                                       stmmac_pltfr_resume);
 EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
+
+MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_LICENSE("GPL");
index 0c5842aeb807014c632a2d713b366133d7021f56..ab6051a43134f4dd7296679ffe089203162e3aa7 100644 (file)
@@ -6658,10 +6658,8 @@ static netdev_tx_t niu_start_xmit(struct sk_buff *skb,
                struct sk_buff *skb_new;
 
                skb_new = skb_realloc_headroom(skb, len);
-               if (!skb_new) {
-                       rp->tx_errors++;
+               if (!skb_new)
                        goto out_drop;
-               }
                kfree_skb(skb);
                skb = skb_new;
        } else
index 462820514faea05beaa77f5a7e94ede318c294c6..d155bf2573cd0ef00abc133074831cccc7f937b1 100644 (file)
@@ -138,19 +138,6 @@ do {                                                               \
 #define CPSW_CMINTMAX_INTVL    (1000 / CPSW_CMINTMIN_CNT)
 #define CPSW_CMINTMIN_INTVL    ((1000 / CPSW_CMINTMAX_CNT) + 1)
 
-#define cpsw_enable_irq(priv)  \
-       do {                    \
-               u32 i;          \
-               for (i = 0; i < priv->num_irqs; i++) \
-                       enable_irq(priv->irqs_table[i]); \
-       } while (0)
-#define cpsw_disable_irq(priv) \
-       do {                    \
-               u32 i;          \
-               for (i = 0; i < priv->num_irqs; i++) \
-                       disable_irq_nosync(priv->irqs_table[i]); \
-       } while (0)
-
 #define cpsw_slave_index(priv)                         \
                ((priv->data.dual_emac) ? priv->emac_port :     \
                priv->data.active_slave)
@@ -509,9 +496,11 @@ static const struct cpsw_stats cpsw_gstrings_stats[] = {
                                (func)(slave++, ##arg);                 \
        } while (0)
 #define cpsw_get_slave_ndev(priv, __slave_no__)                                \
-       (priv->slaves[__slave_no__].ndev)
+       ((__slave_no__ < priv->data.slaves) ?                           \
+               priv->slaves[__slave_no__].ndev : NULL)
 #define cpsw_get_slave_priv(priv, __slave_no__)                                \
-       ((priv->slaves[__slave_no__].ndev) ?                            \
+       (((__slave_no__ < priv->data.slaves) &&                         \
+               (priv->slaves[__slave_no__].ndev)) ?                    \
                netdev_priv(priv->slaves[__slave_no__].ndev) : NULL)    \
 
 #define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb)                \
@@ -781,7 +770,7 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
 
        cpsw_intr_disable(priv);
        if (priv->irq_enabled == true) {
-               cpsw_disable_irq(priv);
+               disable_irq_nosync(priv->irqs_table[0]);
                priv->irq_enabled = false;
        }
 
@@ -804,9 +793,7 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
 static int cpsw_poll(struct napi_struct *napi, int budget)
 {
        struct cpsw_priv        *priv = napi_to_priv(napi);
-       int                     num_tx, num_rx;
-
-       num_tx = cpdma_chan_process(priv->txch, 128);
+       int                     num_rx;
 
        num_rx = cpdma_chan_process(priv->rxch, budget);
        if (num_rx < budget) {
@@ -817,13 +804,12 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
                prim_cpsw = cpsw_get_slave_priv(priv, 0);
                if (prim_cpsw->irq_enabled == false) {
                        prim_cpsw->irq_enabled = true;
-                       cpsw_enable_irq(priv);
+                       enable_irq(priv->irqs_table[0]);
                }
        }
 
-       if (num_rx || num_tx)
-               cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n",
-                        num_rx, num_tx);
+       if (num_rx)
+               cpsw_dbg(priv, intr, "poll %d rx pkts\n", num_rx);
 
        return num_rx;
 }
@@ -1333,7 +1319,7 @@ static int cpsw_ndo_open(struct net_device *ndev)
        if (prim_cpsw->irq_enabled == false) {
                if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) {
                        prim_cpsw->irq_enabled = true;
-                       cpsw_enable_irq(prim_cpsw);
+                       enable_irq(prim_cpsw->irqs_table[0]);
                }
        }
 
index bbacf5cccec2fcbc3831e8f61b559d51a5211816..bb1bb72121c0474b8c1898540a28d21264479d6a 100644 (file)
@@ -85,7 +85,6 @@ struct netcp_intf {
        struct list_head        rxhook_list_head;
        unsigned int            rx_queue_id;
        void                    *rx_fdq[KNAV_DMA_FDQ_PER_CHAN];
-       u32                     rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN];
        struct napi_struct      rx_napi;
        struct napi_struct      tx_napi;
 
@@ -223,6 +222,7 @@ void *netcp_device_find_module(struct netcp_device *netcp_device,
 
 /* SGMII functions */
 int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port);
+bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set);
 int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port);
 int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface);
 
index 5ec4ed3f6c8def7a6a6cf527cd9ac7ca73c09844..4755838c6137b462d6de262b38beadacdf099e98 100644 (file)
@@ -34,6 +34,7 @@
 #define NETCP_SOP_OFFSET       (NET_IP_ALIGN + NET_SKB_PAD)
 #define NETCP_NAPI_WEIGHT      64
 #define NETCP_TX_TIMEOUT       (5 * HZ)
+#define NETCP_PACKET_SIZE      (ETH_FRAME_LEN + ETH_FCS_LEN)
 #define NETCP_MIN_PACKET_SIZE  ETH_ZLEN
 #define NETCP_MAX_MCAST_ADDR   16
 
@@ -804,30 +805,28 @@ static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
        if (likely(fdq == 0)) {
                unsigned int primary_buf_len;
                /* Allocate a primary receive queue entry */
-               buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET;
+               buf_len = NETCP_PACKET_SIZE + NETCP_SOP_OFFSET;
                primary_buf_len = SKB_DATA_ALIGN(buf_len) +
                                SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
-               if (primary_buf_len <= PAGE_SIZE) {
-                       bufptr = netdev_alloc_frag(primary_buf_len);
-                       pad[1] = primary_buf_len;
-               } else {
-                       bufptr = kmalloc(primary_buf_len, GFP_ATOMIC |
-                                        GFP_DMA32 | __GFP_COLD);
-                       pad[1] = 0;
-               }
+               bufptr = netdev_alloc_frag(primary_buf_len);
+               pad[1] = primary_buf_len;
 
                if (unlikely(!bufptr)) {
-                       dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n");
+                       dev_warn_ratelimited(netcp->ndev_dev,
+                                            "Primary RX buffer alloc failed\n");
                        goto fail;
                }
                dma = dma_map_single(netcp->dev, bufptr, buf_len,
                                     DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(netcp->dev, dma)))
+                       goto fail;
+
                pad[0] = (u32)bufptr;
 
        } else {
                /* Allocate a secondary receive queue entry */
-               page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD);
+               page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD);
                if (unlikely(!page)) {
                        dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n");
                        goto fail;
@@ -1010,7 +1009,7 @@ netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp)
 
        /* Map the linear buffer */
        dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE);
-       if (unlikely(!dma_addr)) {
+       if (unlikely(dma_mapping_error(dev, dma_addr))) {
                dev_err(netcp->ndev_dev, "Failed to map skb buffer\n");
                return NULL;
        }
@@ -1546,8 +1545,8 @@ static int netcp_setup_navigator_resources(struct net_device *ndev)
        knav_queue_disable_notify(netcp->rx_queue);
 
        /* open Rx FDQs */
-       for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN &&
-            netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) {
+       for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_queue_depths[i];
+            ++i) {
                snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i);
                netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0);
                if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) {
@@ -1617,11 +1616,11 @@ static int netcp_ndo_open(struct net_device *ndev)
        }
        mutex_unlock(&netcp_modules_lock);
 
-       netcp_rxpool_refill(netcp);
        napi_enable(&netcp->rx_napi);
        napi_enable(&netcp->tx_napi);
        knav_queue_enable_notify(netcp->tx_compl_q);
        knav_queue_enable_notify(netcp->rx_queue);
+       netcp_rxpool_refill(netcp);
        netif_tx_wake_all_queues(ndev);
        dev_dbg(netcp->ndev_dev, "netcp device %s opened\n", ndev->name);
        return 0;
@@ -1941,14 +1940,6 @@ static int netcp_create_interface(struct netcp_device *netcp_device,
                netcp->rx_queue_depths[0] = 128;
        }
 
-       ret = of_property_read_u32_array(node_interface, "rx-buffer-size",
-                                        netcp->rx_buffer_sizes,
-                                        KNAV_DMA_FDQ_PER_CHAN);
-       if (ret) {
-               dev_err(dev, "missing \"rx-buffer-size\" parameter\n");
-               netcp->rx_buffer_sizes[0] = 1536;
-       }
-
        ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2);
        if (ret < 0) {
                dev_err(dev, "missing \"rx-pool\" parameter\n");
@@ -2112,6 +2103,7 @@ probe_quit:
 static int netcp_remove(struct platform_device *pdev)
 {
        struct netcp_device *netcp_device = platform_get_drvdata(pdev);
+       struct netcp_intf *netcp_intf, *netcp_tmp;
        struct netcp_inst_modpriv *inst_modpriv, *tmp;
        struct netcp_module *module;
 
@@ -2123,10 +2115,17 @@ static int netcp_remove(struct platform_device *pdev)
                list_del(&inst_modpriv->inst_list);
                kfree(inst_modpriv);
        }
-       WARN(!list_empty(&netcp_device->interface_head), "%s interface list not empty!\n",
-            pdev->name);
 
-       devm_kfree(&pdev->dev, netcp_device);
+       /* now that all modules are removed, clean up the interfaces */
+       list_for_each_entry_safe(netcp_intf, netcp_tmp,
+                                &netcp_device->interface_head,
+                                interface_list) {
+               netcp_delete_interface(netcp_device, netcp_intf->ndev);
+       }
+
+       WARN(!list_empty(&netcp_device->interface_head),
+            "%s interface list not empty!\n", pdev->name);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
index 9b7e0a34c98b10aca5eed610c47f33b2eedbbd00..1974a8ae764aba6cb81e039239df68e91a58585b 100644 (file)
@@ -1901,11 +1901,28 @@ static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
        writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control));
 }
 
+static void gbe_sgmii_rtreset(struct gbe_priv *priv,
+                             struct gbe_slave *slave, bool set)
+{
+       void __iomem *sgmii_port_regs;
+
+       if (SLAVE_LINK_IS_XGMII(slave))
+               return;
+
+       if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2))
+               sgmii_port_regs = priv->sgmii_port34_regs;
+       else
+               sgmii_port_regs = priv->sgmii_port_regs;
+
+       netcp_sgmii_rtreset(sgmii_port_regs, slave->slave_num, set);
+}
+
 static void gbe_slave_stop(struct gbe_intf *intf)
 {
        struct gbe_priv *gbe_dev = intf->gbe_dev;
        struct gbe_slave *slave = intf->slave;
 
+       gbe_sgmii_rtreset(gbe_dev, slave, true);
        gbe_port_reset(slave);
        /* Disable forwarding */
        cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
@@ -1947,6 +1964,7 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf)
 
        gbe_sgmii_config(priv, slave);
        gbe_port_reset(slave);
+       gbe_sgmii_rtreset(priv, slave, false);
        gbe_port_config(priv, slave, priv->rx_packet_max);
        gbe_set_slave_mac(slave, gbe_intf);
        /* enable forwarding */
@@ -2490,10 +2508,9 @@ static void free_secondary_ports(struct gbe_priv *gbe_dev)
 {
        struct gbe_slave *slave;
 
-       for (;;) {
+       while (!list_empty(&gbe_dev->secondary_slaves)) {
                slave = first_sec_slave(gbe_dev);
-               if (!slave)
-                       break;
+
                if (slave->phy)
                        phy_disconnect(slave->phy);
                list_del(&slave->slave_list);
@@ -2839,14 +2856,13 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
                                      &gbe_dev->dma_chan_name);
        if (ret < 0) {
                dev_err(dev, "missing \"tx-channel\" parameter\n");
-               ret = -ENODEV;
-               goto quit;
+               return -EINVAL;
        }
 
        if (!strcmp(node->name, "gbe")) {
                ret = get_gbe_resource_version(gbe_dev, node);
                if (ret)
-                       goto quit;
+                       return ret;
 
                dev_dbg(dev, "ss_version: 0x%08x\n", gbe_dev->ss_version);
 
@@ -2857,22 +2873,20 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
                else
                        ret = -ENODEV;
 
-               if (ret)
-                       goto quit;
        } else if (!strcmp(node->name, "xgbe")) {
                ret = set_xgbe_ethss10_priv(gbe_dev, node);
                if (ret)
-                       goto quit;
+                       return ret;
                ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs,
                                             gbe_dev->ss_regs);
-               if (ret)
-                       goto quit;
        } else {
                dev_err(dev, "unknown GBE node(%s)\n", node->name);
                ret = -ENODEV;
-               goto quit;
        }
 
+       if (ret)
+               return ret;
+
        interfaces = of_get_child_by_name(node, "interfaces");
        if (!interfaces)
                dev_err(dev, "could not find interfaces\n");
@@ -2880,11 +2894,11 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device,
                                gbe_dev->dma_chan_name, gbe_dev->tx_queue_id);
        if (ret)
-               goto quit;
+               return ret;
 
        ret = netcp_txpipe_open(&gbe_dev->tx_pipe);
        if (ret)
-               goto quit;
+               return ret;
 
        /* Create network interfaces */
        INIT_LIST_HEAD(&gbe_dev->gbe_intf_head);
@@ -2899,6 +2913,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
                if (gbe_dev->num_slaves >= gbe_dev->max_num_slaves)
                        break;
        }
+       of_node_put(interfaces);
 
        if (!gbe_dev->num_slaves)
                dev_warn(dev, "No network interface configured\n");
@@ -2911,9 +2926,10 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        of_node_put(secondary_ports);
 
        if (!gbe_dev->num_slaves) {
-               dev_err(dev, "No network interface or secondary ports configured\n");
+               dev_err(dev,
+                       "No network interface or secondary ports configured\n");
                ret = -ENODEV;
-               goto quit;
+               goto free_sec_ports;
        }
 
        memset(&ale_params, 0, sizeof(ale_params));
@@ -2927,7 +2943,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        if (!gbe_dev->ale) {
                dev_err(gbe_dev->dev, "error initializing ale engine\n");
                ret = -ENODEV;
-               goto quit;
+               goto free_sec_ports;
        } else {
                dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
        }
@@ -2943,14 +2959,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
        *inst_priv = gbe_dev;
        return 0;
 
-quit:
-       if (gbe_dev->hw_stats)
-               devm_kfree(dev, gbe_dev->hw_stats);
-       cpsw_ale_destroy(gbe_dev->ale);
-       if (gbe_dev->ss_regs)
-               devm_iounmap(dev, gbe_dev->ss_regs);
-       of_node_put(interfaces);
-       devm_kfree(dev, gbe_dev);
+free_sec_ports:
+       free_secondary_ports(gbe_dev);
        return ret;
 }
 
@@ -3023,12 +3033,9 @@ static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv)
        free_secondary_ports(gbe_dev);
 
        if (!list_empty(&gbe_dev->gbe_intf_head))
-               dev_alert(gbe_dev->dev, "unreleased ethss interfaces present\n");
+               dev_alert(gbe_dev->dev,
+                         "unreleased ethss interfaces present\n");
 
-       devm_kfree(gbe_dev->dev, gbe_dev->hw_stats);
-       devm_iounmap(gbe_dev->dev, gbe_dev->ss_regs);
-       memset(gbe_dev, 0x00, sizeof(*gbe_dev));
-       devm_kfree(gbe_dev->dev, gbe_dev);
        return 0;
 }
 
index dbeb14266e2fb106c8a16b7d32b73fbc28095ec7..5d8419f658d04397a7be30c2a1b9a249f492e6e8 100644 (file)
@@ -18,6 +18,9 @@
 
 #include "netcp.h"
 
+#define SGMII_SRESET_RESET             BIT(0)
+#define SGMII_SRESET_RTRESET           BIT(1)
+
 #define SGMII_REG_STATUS_LOCK          BIT(4)
 #define        SGMII_REG_STATUS_LINK           BIT(0)
 #define SGMII_REG_STATUS_AUTONEG       BIT(2)
@@ -51,12 +54,35 @@ static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
 int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
 {
        /* Soft reset */
-       sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1);
-       while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0)
+       sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port),
+                           SGMII_SRESET_RESET);
+
+       while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) &
+               SGMII_SRESET_RESET) != 0x0)
                ;
+
        return 0;
 }
 
+/* port is 0 based */
+bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set)
+{
+       u32 reg;
+       bool oldval;
+
+       /* Initiate a soft reset */
+       reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port));
+       oldval = (reg & SGMII_SRESET_RTRESET) != 0x0;
+       if (set)
+               reg |= SGMII_SRESET_RTRESET;
+       else
+               reg &= ~SGMII_SRESET_RTRESET;
+       sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg);
+       wmb();
+
+       return oldval;
+}
+
 int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
 {
        u32 status = 0, link = 0;
index 4208dd7ef10118aff0fa4bf02cd47e05481c25f9..d95f9aae95e78ecc08b8a91bb67c267d10f81461 100644 (file)
@@ -1530,9 +1530,9 @@ static int axienet_probe(struct platform_device *pdev)
        /* Map device registers */
        ethres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        lp->regs = devm_ioremap_resource(&pdev->dev, ethres);
-       if (!lp->regs) {
+       if (IS_ERR(lp->regs)) {
                dev_err(&pdev->dev, "could not map Axi Ethernet regs.\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(lp->regs);
                goto free_netdev;
        }
 
@@ -1599,9 +1599,9 @@ static int axienet_probe(struct platform_device *pdev)
                goto free_netdev;
        }
        lp->dma_regs = devm_ioremap_resource(&pdev->dev, &dmares);
-       if (!lp->dma_regs) {
+       if (IS_ERR(lp->dma_regs)) {
                dev_err(&pdev->dev, "could not map DMA regs\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(lp->dma_regs);
                goto free_netdev;
        }
        lp->rx_irq = irq_of_parse_and_map(np, 1);
index 7856b6ccf5c547e5c4eaf790d111f40527c375fa..d95a50ae996dd4d57f78e67b51a7a3e79f8caaf3 100644 (file)
@@ -482,6 +482,7 @@ static void bpq_setup(struct net_device *dev)
        memcpy(dev->dev_addr,  &ax25_defaddr, AX25_ADDR_LEN);
 
        dev->flags      = 0;
+       dev->features   = NETIF_F_LLTX; /* Allow recursion */
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
        dev->header_ops      = &ax25_header_ops;
index 2ffbf13471d09ad4c27d8c70fbb4dd3145befa75..216bfd350169a9da723035876d152e89b17c8432 100644 (file)
@@ -728,11 +728,12 @@ static int mkiss_open(struct tty_struct *tty)
        dev->type = ARPHRD_AX25;
 
        /* Perform the low-level AX25 initialization. */
-       if ((err = ax_open(ax->dev))) {
+       err = ax_open(ax->dev);
+       if (err)
                goto out_free_netdev;
-       }
 
-       if (register_netdev(dev))
+       err = register_netdev(dev);
+       if (err)
                goto out_free_buffers;
 
        /* after register_netdev() - because else printk smashes the kernel */
index 953a97492fabf46eda9986ad713e4cc9ec4275dd..9542b7bac61afab0f4537d91f8cc004160521f85 100644 (file)
@@ -67,8 +67,6 @@ struct ipvl_dev {
        struct ipvl_port        *port;
        struct net_device       *phy_dev;
        struct list_head        addrs;
-       int                     ipv4cnt;
-       int                     ipv6cnt;
        struct ipvl_pcpu_stats  __percpu *pcpu_stats;
        DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE);
        netdev_features_t       sfeatures;
@@ -106,6 +104,11 @@ static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d)
        return rcu_dereference(d->rx_handler_data);
 }
 
+static inline struct ipvl_port *ipvlan_port_get_rcu_bh(const struct net_device *d)
+{
+       return rcu_dereference_bh(d->rx_handler_data);
+}
+
 static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d)
 {
        return rtnl_dereference(d->rx_handler_data);
@@ -124,5 +127,5 @@ struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
 bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6);
 struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
                                        const void *iaddr, bool is_v6);
-void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync);
+void ipvlan_ht_addr_del(struct ipvl_addr *addr);
 #endif /* __IPVLAN_H */
index 8afbedad620d9ed27576dc6426878ae858979a51..207f62e8de9a93415cc76eb5fd75f987b3de53b6 100644 (file)
@@ -85,11 +85,9 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
                hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
 }
 
-void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync)
+void ipvlan_ht_addr_del(struct ipvl_addr *addr)
 {
        hlist_del_init_rcu(&addr->hlnode);
-       if (sync)
-               synchronize_rcu();
 }
 
 struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
@@ -531,7 +529,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
 int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ipvl_dev *ipvlan = netdev_priv(dev);
-       struct ipvl_port *port = ipvlan_port_get_rcu(ipvlan->phy_dev);
+       struct ipvl_port *port = ipvlan_port_get_rcu_bh(ipvlan->phy_dev);
 
        if (!port)
                goto out;
index 1acc283160d924e0754f3da99fc120c638c257a2..20b58bdecf7540100edc5522e74804e6a7544d95 100644 (file)
@@ -153,10 +153,9 @@ static int ipvlan_open(struct net_device *dev)
        else
                dev->flags &= ~IFF_NOARP;
 
-       if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
-               list_for_each_entry(addr, &ipvlan->addrs, anode)
-                       ipvlan_ht_addr_add(ipvlan, addr);
-       }
+       list_for_each_entry(addr, &ipvlan->addrs, anode)
+               ipvlan_ht_addr_add(ipvlan, addr);
+
        return dev_uc_add(phy_dev, phy_dev->dev_addr);
 }
 
@@ -171,10 +170,9 @@ static int ipvlan_stop(struct net_device *dev)
 
        dev_uc_del(phy_dev, phy_dev->dev_addr);
 
-       if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
-               list_for_each_entry(addr, &ipvlan->addrs, anode)
-                       ipvlan_ht_addr_del(addr, !dev->dismantle);
-       }
+       list_for_each_entry(addr, &ipvlan->addrs, anode)
+               ipvlan_ht_addr_del(addr);
+
        return 0;
 }
 
@@ -471,8 +469,6 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
        ipvlan->port = port;
        ipvlan->sfeatures = IPVLAN_FEATURES;
        INIT_LIST_HEAD(&ipvlan->addrs);
-       ipvlan->ipv4cnt = 0;
-       ipvlan->ipv6cnt = 0;
 
        /* TODO Probably put random address here to be presented to the
         * world but keep using the physical-dev address for the outgoing
@@ -508,12 +504,12 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
        struct ipvl_dev *ipvlan = netdev_priv(dev);
        struct ipvl_addr *addr, *next;
 
-       if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) {
-               list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
-                       ipvlan_ht_addr_del(addr, !dev->dismantle);
-                       list_del(&addr->anode);
-               }
+       list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) {
+               ipvlan_ht_addr_del(addr);
+               list_del(&addr->anode);
+               kfree_rcu(addr, rcu);
        }
+
        list_del_rcu(&ipvlan->pnode);
        unregister_netdevice_queue(dev, head);
        netdev_upper_dev_unlink(ipvlan->phy_dev, dev);
@@ -627,7 +623,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
        addr->atype = IPVL_IPV6;
        list_add_tail(&addr->anode, &ipvlan->addrs);
-       ipvlan->ipv6cnt++;
+
        /* If the interface is not up, the address will be added to the hash
         * list by ipvlan_open.
         */
@@ -645,10 +641,8 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
        if (!addr)
                return;
 
-       ipvlan_ht_addr_del(addr, true);
+       ipvlan_ht_addr_del(addr);
        list_del(&addr->anode);
-       ipvlan->ipv6cnt--;
-       WARN_ON(ipvlan->ipv6cnt < 0);
        kfree_rcu(addr, rcu);
 
        return;
@@ -661,6 +655,10 @@ static int ipvlan_addr6_event(struct notifier_block *unused,
        struct net_device *dev = (struct net_device *)if6->idev->dev;
        struct ipvl_dev *ipvlan = netdev_priv(dev);
 
+       /* FIXME IPv6 autoconf calls us from bh without RTNL */
+       if (in_softirq())
+               return NOTIFY_DONE;
+
        if (!netif_is_ipvlan(dev))
                return NOTIFY_DONE;
 
@@ -699,7 +697,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
        addr->atype = IPVL_IPV4;
        list_add_tail(&addr->anode, &ipvlan->addrs);
-       ipvlan->ipv4cnt++;
+
        /* If the interface is not up, the address will be added to the hash
         * list by ipvlan_open.
         */
@@ -717,10 +715,8 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
        if (!addr)
                return;
 
-       ipvlan_ht_addr_del(addr, true);
+       ipvlan_ht_addr_del(addr);
        list_del(&addr->anode);
-       ipvlan->ipv4cnt--;
-       WARN_ON(ipvlan->ipv4cnt < 0);
        kfree_rcu(addr, rcu);
 
        return;
index f8370808a018f77503de49503985f3d5c55985f6..edd77342773a8d4ef0713717adfa5bcf6bdf44f7 100644 (file)
@@ -719,6 +719,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
        struct virtio_net_hdr vnet_hdr = { 0 };
        int vnet_hdr_len = 0;
        int copylen = 0;
+       int depth;
        bool zerocopy = false;
        size_t linear;
        ssize_t n;
@@ -804,6 +805,12 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        skb_probe_transport_header(skb, ETH_HLEN);
 
+       /* Move network header to the right position for VLAN tagged packets */
+       if ((skb->protocol == htons(ETH_P_8021Q) ||
+            skb->protocol == htons(ETH_P_8021AD)) &&
+           __vlan_get_protocol(skb, skb->protocol, &depth) != 0)
+               skb_set_network_header(skb, depth);
+
        rcu_read_lock();
        vlan = rcu_dereference(q->vlan);
        /* copy skb_ubuf_info for callback when skb has no error */
@@ -1355,6 +1362,7 @@ static void macvtap_exit(void)
        class_unregister(macvtap_class);
        cdev_del(&macvtap_cdev);
        unregister_chrdev_region(macvtap_major, MACVTAP_NUM_DEVS);
+       idr_destroy(&minor_idr);
 }
 module_exit(macvtap_exit);
 
index 3cc316cb7e6be792b06dfc2c520eae9809f1008b..d8757bf9ad755ed6a3114d9d0a9664e59618744a 100644 (file)
@@ -102,6 +102,12 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
 
        netdev_dbg(ndev, "%s: %d byte payload received\n", __func__, len);
 
+       if (len < 0) {
+               ndev->stats.rx_errors++;
+               ndev->stats.rx_length_errors++;
+               goto enqueue_again;
+       }
+
        skb_put(skb, len);
        skb->protocol = eth_type_trans(skb, ndev);
        skb->ip_summed = CHECKSUM_NONE;
@@ -121,6 +127,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
                return;
        }
 
+enqueue_again:
        rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
        if (rc) {
                dev_kfree_skb(skb);
@@ -184,7 +191,7 @@ static int ntb_netdev_open(struct net_device *ndev)
 
                rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
                                              ndev->mtu + ETH_HLEN);
-               if (rc == -EINVAL) {
+               if (rc) {
                        dev_kfree_skb(skb);
                        goto err;
                }
index cf18940f4e84f5352a6dffe7a72548d72ef3a011..cb86d7a0154228f5c3711898072a0e5f5d4d6a81 100644 (file)
@@ -191,7 +191,7 @@ config MDIO_BUS_MUX_GPIO
 
 config MDIO_BUS_MUX_MMIOREG
        tristate "Support for MMIO device-controlled MDIO bus multiplexers"
-       depends on OF_MDIO
+       depends on OF_MDIO && HAS_IOMEM
        select MDIO_BUS_MUX
        help
          This module provides a driver for MDIO bus multiplexers that
index c7a12e2e07b7670a55a682ea2988cc4cca86d7b7..8a3bf546989212734aa9a5a5a5b58948ecf264da 100644 (file)
@@ -164,7 +164,7 @@ static int dp83867_config_init(struct phy_device *phydev)
                        return ret;
        }
 
-       if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) ||
+       if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) &&
            (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) {
                val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL,
                                            DP83867_DEVADDR, phydev->addr);
index 095ef3fe369af5ebe08254384abc38176df1aef1..46a14cbb021541095a22016a7ad712d79db9307a 100644 (file)
@@ -421,6 +421,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct phy_device *phydev = to_phy_device(dev);
        struct phy_driver *phydrv = to_phy_driver(drv);
+       const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
+       int i;
 
        if (of_driver_match_device(dev, drv))
                return 1;
@@ -428,8 +430,21 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
        if (phydrv->match_phy_device)
                return phydrv->match_phy_device(phydev);
 
-       return (phydrv->phy_id & phydrv->phy_id_mask) ==
-               (phydev->phy_id & phydrv->phy_id_mask);
+       if (phydev->is_c45) {
+               for (i = 1; i < num_ids; i++) {
+                       if (!(phydev->c45_ids.devices_in_package & (1 << i)))
+                               continue;
+
+                       if ((phydrv->phy_id & phydrv->phy_id_mask) ==
+                           (phydev->c45_ids.device_ids[i] &
+                            phydrv->phy_id_mask))
+                               return 1;
+               }
+               return 0;
+       } else {
+               return (phydrv->phy_id & phydrv->phy_id_mask) ==
+                       (phydev->phy_id & phydrv->phy_id_mask);
+       }
 }
 
 #ifdef CONFIG_PM
index b2197b506acbe86f3540d5ae1d8334129c2bbe57..1e1fbb049ec63b79c1d8255c517364f739a8d38b 100644 (file)
@@ -811,6 +811,7 @@ void phy_state_machine(struct work_struct *work)
        bool needs_aneg = false, do_suspend = false;
        enum phy_state old_state;
        int err = 0;
+       int old_link;
 
        mutex_lock(&phydev->lock);
 
@@ -896,11 +897,18 @@ void phy_state_machine(struct work_struct *work)
                phydev->adjust_link(phydev->attached_dev);
                break;
        case PHY_RUNNING:
-               /* Only register a CHANGE if we are
-                * polling or ignoring interrupts
+               /* Only register a CHANGE if we are polling or ignoring
+                * interrupts and link changed since latest checking.
                 */
-               if (!phy_interrupt_is_valid(phydev))
-                       phydev->state = PHY_CHANGELINK;
+               if (!phy_interrupt_is_valid(phydev)) {
+                       old_link = phydev->link;
+                       err = phy_read_status(phydev);
+                       if (err)
+                               break;
+
+                       if (old_link != phydev->link)
+                               phydev->state = PHY_CHANGELINK;
+               }
                break;
        case PHY_CHANGELINK:
                err = phy_read_status(phydev);
index c0f6479e19d48e51fd76c3bbce161ffdd7846842..70b08958763a129fff47ad00a1db130c1334f254 100644 (file)
@@ -91,19 +91,18 @@ static int lan911x_config_init(struct phy_device *phydev)
 }
 
 /*
- * The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each
- * other in order to set the ENERGYON bit and exit EDPD mode.  If a link partner
- * does send the pulses within this interval, the PHY will remained powered
- * down.
- *
- * This workaround will manually toggle the PHY on/off upon calls to read_status
- * in order to generate link test pulses if the link is down.  If a link partner
- * is present, it will respond to the pulses, which will cause the ENERGYON bit
- * to be set and will cause the EDPD mode to be exited.
+ * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
+ * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
+ * unstable detection of plugging in Ethernet cable.
+ * This workaround disables Energy Detect Power-Down mode and waiting for
+ * response on link pulses to detect presence of plugged Ethernet cable.
+ * The Energy Detect Power-Down mode is enabled again in the end of procedure to
+ * save approximately 220 mW of power if cable is unplugged.
  */
 static int lan87xx_read_status(struct phy_device *phydev)
 {
        int err = genphy_read_status(phydev);
+       int i;
 
        if (!phydev->link) {
                /* Disable EDPD to wake up PHY */
@@ -116,8 +115,16 @@ static int lan87xx_read_status(struct phy_device *phydev)
                if (rc < 0)
                        return rc;
 
-               /* Sleep 64 ms to allow ~5 link test pulses to be sent */
-               msleep(64);
+               /* Wait max 640 ms to detect energy */
+               for (i = 0; i < 64; i++) {
+                       /* Sleep to allow link test pulses to be sent */
+                       msleep(10);
+                       rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+                       if (rc < 0)
+                               return rc;
+                       if (rc & MII_LAN83C185_ENERGYON)
+                               break;
+               }
 
                /* Re-enable EDPD */
                rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
@@ -191,7 +198,7 @@ static struct phy_driver smsc_phy_driver[] = {
 
        /* basic functions */
        .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
+       .read_status    = lan87xx_read_status,
        .config_init    = smsc_phy_config_init,
        .soft_reset     = smsc_phy_reset,
 
index 9d15566521a719b525a28a009f1d999c91a00da2..fa8f5046afe90627242f6d2d523178da653c9427 100644 (file)
@@ -269,9 +269,9 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound);
 static void ppp_ccp_closed(struct ppp *ppp);
 static struct compressor *find_compressor(int type);
 static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
-static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp);
+static struct ppp *ppp_create_interface(struct net *net, int unit,
+                                       struct file *file, int *retp);
 static void init_ppp_file(struct ppp_file *pf, int kind);
-static void ppp_shutdown_interface(struct ppp *ppp);
 static void ppp_destroy_interface(struct ppp *ppp);
 static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit);
 static struct channel *ppp_find_channel(struct ppp_net *pn, int unit);
@@ -392,8 +392,10 @@ static int ppp_release(struct inode *unused, struct file *file)
                file->private_data = NULL;
                if (pf->kind == INTERFACE) {
                        ppp = PF_TO_PPP(pf);
+                       rtnl_lock();
                        if (file == ppp->owner)
-                               ppp_shutdown_interface(ppp);
+                               unregister_netdevice(ppp->dev);
+                       rtnl_unlock();
                }
                if (atomic_dec_and_test(&pf->refcnt)) {
                        switch (pf->kind) {
@@ -593,8 +595,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                mutex_lock(&ppp_mutex);
                if (pf->kind == INTERFACE) {
                        ppp = PF_TO_PPP(pf);
+                       rtnl_lock();
                        if (file == ppp->owner)
-                               ppp_shutdown_interface(ppp);
+                               unregister_netdevice(ppp->dev);
+                       rtnl_unlock();
                }
                if (atomic_long_read(&file->f_count) < 2) {
                        ppp_release(NULL, file);
@@ -838,11 +842,10 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
                /* Create a new ppp unit */
                if (get_user(unit, p))
                        break;
-               ppp = ppp_create_interface(net, unit, &err);
+               ppp = ppp_create_interface(net, unit, file, &err);
                if (!ppp)
                        break;
                file->private_data = &ppp->file;
-               ppp->owner = file;
                err = -EFAULT;
                if (put_user(ppp->file.index, p))
                        break;
@@ -916,6 +919,16 @@ static __net_init int ppp_init_net(struct net *net)
 static __net_exit void ppp_exit_net(struct net *net)
 {
        struct ppp_net *pn = net_generic(net, ppp_net_id);
+       struct ppp *ppp;
+       LIST_HEAD(list);
+       int id;
+
+       rtnl_lock();
+       idr_for_each_entry(&pn->units_idr, ppp, id)
+               unregister_netdevice_queue(ppp->dev, &list);
+
+       unregister_netdevice_many(&list);
+       rtnl_unlock();
 
        idr_destroy(&pn->units_idr);
 }
@@ -1088,8 +1101,28 @@ static int ppp_dev_init(struct net_device *dev)
        return 0;
 }
 
+static void ppp_dev_uninit(struct net_device *dev)
+{
+       struct ppp *ppp = netdev_priv(dev);
+       struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
+
+       ppp_lock(ppp);
+       ppp->closing = 1;
+       ppp_unlock(ppp);
+
+       mutex_lock(&pn->all_ppp_mutex);
+       unit_put(&pn->units_idr, ppp->file.index);
+       mutex_unlock(&pn->all_ppp_mutex);
+
+       ppp->owner = NULL;
+
+       ppp->file.dead = 1;
+       wake_up_interruptible(&ppp->file.rwait);
+}
+
 static const struct net_device_ops ppp_netdev_ops = {
        .ndo_init        = ppp_dev_init,
+       .ndo_uninit      = ppp_dev_uninit,
        .ndo_start_xmit  = ppp_start_xmit,
        .ndo_do_ioctl    = ppp_net_ioctl,
        .ndo_get_stats64 = ppp_get_stats64,
@@ -2667,8 +2700,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
  * or if there is already a unit with the requested number.
  * unit == -1 means allocate a new number.
  */
-static struct ppp *
-ppp_create_interface(struct net *net, int unit, int *retp)
+static struct ppp *ppp_create_interface(struct net *net, int unit,
+                                       struct file *file, int *retp)
 {
        struct ppp *ppp;
        struct ppp_net *pn;
@@ -2688,6 +2721,7 @@ ppp_create_interface(struct net *net, int unit, int *retp)
        ppp->mru = PPP_MRU;
        init_ppp_file(&ppp->file, INTERFACE);
        ppp->file.hdrlen = PPP_HDRLEN - 2;      /* don't count proto bytes */
+       ppp->owner = file;
        for (i = 0; i < NUM_NP; ++i)
                ppp->npmode[i] = NPMODE_PASS;
        INIT_LIST_HEAD(&ppp->channels);
@@ -2775,34 +2809,6 @@ init_ppp_file(struct ppp_file *pf, int kind)
        init_waitqueue_head(&pf->rwait);
 }
 
-/*
- * Take down a ppp interface unit - called when the owning file
- * (the one that created the unit) is closed or detached.
- */
-static void ppp_shutdown_interface(struct ppp *ppp)
-{
-       struct ppp_net *pn;
-
-       pn = ppp_pernet(ppp->ppp_net);
-       mutex_lock(&pn->all_ppp_mutex);
-
-       /* This will call dev_close() for us. */
-       ppp_lock(ppp);
-       if (!ppp->closing) {
-               ppp->closing = 1;
-               ppp_unlock(ppp);
-               unregister_netdev(ppp->dev);
-               unit_put(&pn->units_idr, ppp->file.index);
-       } else
-               ppp_unlock(ppp);
-
-       ppp->file.dead = 1;
-       ppp->owner = NULL;
-       wake_up_interruptible(&ppp->file.rwait);
-
-       mutex_unlock(&pn->all_ppp_mutex);
-}
-
 /*
  * Free the memory used by a ppp unit.  This is only called once
  * there are no channels connected to the unit and no file structs
index 4545e78840b0d9dc80ae4392b36cfcf588f17c3a..35a2bffe848ad150a3c6bf0e1d66365ae605ac77 100644 (file)
@@ -523,6 +523,7 @@ static const struct driver_info wwan_info = {
 #define REALTEK_VENDOR_ID      0x0bda
 #define SAMSUNG_VENDOR_ID      0x04e8
 #define LENOVO_VENDOR_ID       0x17ef
+#define NVIDIA_VENDOR_ID       0x0955
 
 static const struct usb_device_id      products[] = {
 /* BLACKLIST !!
@@ -710,6 +711,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* NVIDIA Tegra USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(NVIDIA_VENDOR_ID, 0x09ff, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index e4b7a47a825c7f686e48992b23d3f1ee30555d71..efc18e05af0aed216144e91b7a835342a1b30a59 100644 (file)
@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
        if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
                goto err;
 
-       ret = cdc_ncm_bind_common(dev, intf, data_altsetting);
+       ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0);
        if (ret)
                goto err;
 
index 8067b8fbb0eea42b106cc56ffe6bc216ae01f85a..db40175b1a0b081dfcf5c8eb829d935618324d10 100644 (file)
@@ -6,7 +6,7 @@
  * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
  *
  * USB Host Driver for Network Control Model (NCM)
- * http://www.usb.org/developers/devclass_docs/NCM10.zip
+ * http://www.usb.org/developers/docs/devclass_docs/NCM10_012011.zip
  *
  * The NCM encoding, decoding and initialization logic
  * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
@@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
                ctx->tx_curr_skb = NULL;
        }
 
+       kfree(ctx->delayed_ndp16);
+
        kfree(ctx);
 }
 
-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting)
+int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
 {
        const struct usb_cdc_union_desc *union_desc = NULL;
        struct cdc_ncm_ctx *ctx;
@@ -855,6 +857,17 @@ advance:
        /* finish setting up the device specific data */
        cdc_ncm_setup(dev);
 
+       /* Device-specific flags */
+       ctx->drvflags = drvflags;
+
+       /* Allocate the delayed NDP if needed. */
+       if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
+               ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
+               if (!ctx->delayed_ndp16)
+                       goto error2;
+               dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
+       }
+
        /* override ethtool_ops */
        dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
 
@@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
        if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
                return -ENODEV;
 
-       /* The NCM data altsetting is fixed */
-       ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM);
+       /* The NCM data altsetting is fixed, so we hard-coded it.
+        * Additionally, generic NCM devices are assumed to accept arbitrarily
+        * placed NDP.
+        */
+       ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
 
        /*
         * We should get an event when network connection is "connected" or
@@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
        struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
        size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
 
+       /* If NDP should be moved to the end of the NCM package, we can't follow the
+       * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
+       * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
+       */
+       if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
+               if (ctx->delayed_ndp16->dwSignature == sign)
+                       return ctx->delayed_ndp16;
+
        /* follow the chain of NDPs, looking for a match */
        while (ndpoffset) {
                ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
@@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
        }
 
        /* align new NDP */
-       cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
+       if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
+               cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
 
        /* verify that there is room for the NDP and the datagram (reserve) */
        if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size)
@@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
                nth16->wNdpIndex = cpu_to_le16(skb->len);
 
        /* push a new empty NDP */
-       ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
+       if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
+               ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
+       else
+               ndp16 = ctx->delayed_ndp16;
+
        ndp16->dwSignature = sign;
        ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
        return ndp16;
@@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
        struct sk_buff *skb_out;
        u16 n = 0, index, ndplen;
        u8 ready2send = 0;
+       u32 delayed_ndp_size;
+
+       /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
+        * accordingly. Otherwise, we should check here.
+        */
+       if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
+               delayed_ndp_size = ctx->max_ndp_size;
+       else
+               delayed_ndp_size = 0;
 
        /* if there is a remaining skb, it gets priority */
        if (skb != NULL) {
@@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
                cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max);
 
                /* check if we had enough room left for both NDP and frame */
-               if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) {
+               if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) {
                        if (n == 0) {
                                /* won't fit, MTU problem? */
                                dev_kfree_skb_any(skb);
@@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
                /* variables will be reset at next call */
        }
 
+       /* If requested, put NDP at end of frame. */
+       if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
+               nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
+               cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max);
+               nth16->wNdpIndex = cpu_to_le16(skb_out->len);
+               memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size);
+
+               /* Zero out delayed NDP - signature checking will naturally fail. */
+               ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
+       }
+
        /* If collected data size is less or equal ctx->min_tx_pkt
         * bytes, we send buffers as it is. If we get more data, it
         * would be more efficient for USB HS mobile device with DMA
index 735f7dadb9a0740dea86ed58d55df1ae58edf9ef..2680a65cd5e4fde5e333ef1ca1ff5d5ad4091222 100644 (file)
@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev,
        struct usb_driver *subdriver = ERR_PTR(-ENODEV);
        int ret = -ENODEV;
        struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+       int drvflags = 0;
 
        /* altsetting should always be 1 for NCM devices - so we hard-coded
-        * it here
+        * it here. Some huawei devices will need the NDP part of the NCM package to
+        * be at the end of the frame.
         */
-       ret = cdc_ncm_bind_common(usbnet_dev, intf, 1);
+       drvflags |= CDC_NCM_FLAG_NDP_TO_END;
+       ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
        if (ret)
                goto err;
 
index f603f362504bce0c1cb2656e1d29232eb05db846..64a60afbe50cc4ca0ff12b65ad6331a5fcc5e3a7 100644 (file)
@@ -757,6 +757,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
        {QMI_FIXED_INTF(0x1199, 0x901f, 8)},    /* Sierra Wireless EM7355 */
        {QMI_FIXED_INTF(0x1199, 0x9041, 8)},    /* Sierra Wireless MC7305/MC7355 */
+       {QMI_FIXED_INTF(0x1199, 0x9041, 10)},   /* Sierra Wireless MC7305/MC7355 */
        {QMI_FIXED_INTF(0x1199, 0x9051, 8)},    /* Netgear AirCard 340U */
        {QMI_FIXED_INTF(0x1199, 0x9053, 8)},    /* Sierra Wireless Modem */
        {QMI_FIXED_INTF(0x1199, 0x9054, 8)},    /* Sierra Wireless Modem */
@@ -784,6 +785,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81a4, 8)},    /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81a8, 8)},    /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81a9, 8)},    /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
        {QMI_FIXED_INTF(0x03f0, 0x581d, 4)},    /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
 
        /* 4. Gobi 1000 devices */
index aafa1a1898e43de0d3d06e7d8367751473f25142..ad8cbc6c9ee73513d7bc063ca8d41d75abce3038 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/usb/cdc.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v1.08.0 (2015/01/13)"
+#define DRIVER_VERSION "v1.08.1 (2015/07/28)"
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
 #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 #define MODULENAME "r8152"
@@ -494,6 +494,7 @@ enum rtl8152_flags {
 #define VENDOR_ID_REALTEK              0x0bda
 #define VENDOR_ID_SAMSUNG              0x04e8
 #define VENDOR_ID_LENOVO               0x17ef
+#define VENDOR_ID_NVIDIA               0x0955
 
 #define MCU_TYPE_PLA                   0x0100
 #define MCU_TYPE_USB                   0x0000
@@ -1901,11 +1902,10 @@ static void rtl_drop_queued_tx(struct r8152 *tp)
 static void rtl8152_tx_timeout(struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
-       int i;
 
        netif_warn(tp, tx_err, netdev, "Tx timeout\n");
-       for (i = 0; i < RTL8152_MAX_TX; i++)
-               usb_unlink_urb(tp->tx_info[i].urb);
+
+       usb_queue_reset_device(tp->intf);
 }
 
 static void rtl8152_set_rx_mode(struct net_device *netdev)
@@ -2074,7 +2074,6 @@ static int rtl_start_rx(struct r8152 *tp)
 {
        int i, ret = 0;
 
-       napi_disable(&tp->napi);
        INIT_LIST_HEAD(&tp->rx_done);
        for (i = 0; i < RTL8152_MAX_RX; i++) {
                INIT_LIST_HEAD(&tp->rx_info[i].list);
@@ -2082,7 +2081,6 @@ static int rtl_start_rx(struct r8152 *tp)
                if (ret)
                        break;
        }
-       napi_enable(&tp->napi);
 
        if (ret && ++i < RTL8152_MAX_RX) {
                struct list_head rx_queue;
@@ -2165,6 +2163,7 @@ static int rtl8153_enable(struct r8152 *tp)
        if (test_bit(RTL8152_UNPLUG, &tp->flags))
                return -ENODEV;
 
+       usb_disable_lpm(tp->udev);
        set_tx_qlen(tp);
        rtl_set_eee_plus(tp);
        r8153_set_rx_early_timeout(tp);
@@ -2336,11 +2335,61 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
                device_set_wakeup_enable(&tp->udev->dev, false);
 }
 
+static void r8153_u1u2en(struct r8152 *tp, bool enable)
+{
+       u8 u1u2[8];
+
+       if (enable)
+               memset(u1u2, 0xff, sizeof(u1u2));
+       else
+               memset(u1u2, 0x00, sizeof(u1u2));
+
+       usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
+}
+
+static void r8153_u2p3en(struct r8152 *tp, bool enable)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
+       if (enable && tp->version != RTL_VER_03 && tp->version != RTL_VER_04)
+               ocp_data |= U2P3_ENABLE;
+       else
+               ocp_data &= ~U2P3_ENABLE;
+       ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
+}
+
+static void r8153_power_cut_en(struct r8152 *tp, bool enable)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
+       if (enable)
+               ocp_data |= PWR_EN | PHASE2_EN;
+       else
+               ocp_data &= ~(PWR_EN | PHASE2_EN);
+       ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
+       ocp_data &= ~PCUT_STATUS;
+       ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
+}
+
+static bool rtl_can_wakeup(struct r8152 *tp)
+{
+       struct usb_device *udev = tp->udev;
+
+       return (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP);
+}
+
 static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
 {
        if (enable) {
                u32 ocp_data;
 
+               r8153_u1u2en(tp, false);
+               r8153_u2p3en(tp, false);
+
                __rtl_set_wol(tp, WAKE_ANY);
 
                ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
@@ -2352,6 +2401,8 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
                ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
        } else {
                __rtl_set_wol(tp, tp->saved_wolopts);
+               r8153_u2p3en(tp, true);
+               r8153_u1u2en(tp, true);
        }
 }
 
@@ -2598,46 +2649,6 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
        set_bit(PHY_RESET, &tp->flags);
 }
 
-static void r8153_u1u2en(struct r8152 *tp, bool enable)
-{
-       u8 u1u2[8];
-
-       if (enable)
-               memset(u1u2, 0xff, sizeof(u1u2));
-       else
-               memset(u1u2, 0x00, sizeof(u1u2));
-
-       usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
-}
-
-static void r8153_u2p3en(struct r8152 *tp, bool enable)
-{
-       u32 ocp_data;
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
-       if (enable)
-               ocp_data |= U2P3_ENABLE;
-       else
-               ocp_data &= ~U2P3_ENABLE;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
-}
-
-static void r8153_power_cut_en(struct r8152 *tp, bool enable)
-{
-       u32 ocp_data;
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
-       if (enable)
-               ocp_data |= PWR_EN | PHASE2_EN;
-       else
-               ocp_data &= ~(PWR_EN | PHASE2_EN);
-       ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
-       ocp_data &= ~PCUT_STATUS;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
-}
-
 static void r8153_first_init(struct r8152 *tp)
 {
        u32 ocp_data;
@@ -2780,6 +2791,7 @@ static void rtl8153_disable(struct r8152 *tp)
        r8153_disable_aldps(tp);
        rtl_disable(tp);
        r8153_enable_aldps(tp);
+       usb_enable_lpm(tp->udev);
 }
 
 static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
@@ -2900,9 +2912,13 @@ static void rtl8153_up(struct r8152 *tp)
        if (test_bit(RTL8152_UNPLUG, &tp->flags))
                return;
 
+       r8153_u1u2en(tp, false);
        r8153_disable_aldps(tp);
        r8153_first_init(tp);
        r8153_enable_aldps(tp);
+       r8153_u2p3en(tp, true);
+       r8153_u1u2en(tp, true);
+       usb_enable_lpm(tp->udev);
 }
 
 static void rtl8153_down(struct r8152 *tp)
@@ -2913,6 +2929,7 @@ static void rtl8153_down(struct r8152 *tp)
        }
 
        r8153_u1u2en(tp, false);
+       r8153_u2p3en(tp, false);
        r8153_power_cut_en(tp, false);
        r8153_disable_aldps(tp);
        r8153_enter_oob(tp);
@@ -2931,8 +2948,10 @@ static void set_carrier(struct r8152 *tp)
                if (!netif_carrier_ok(netdev)) {
                        tp->rtl_ops.enable(tp);
                        set_bit(RTL8152_SET_RX_MODE, &tp->flags);
+                       napi_disable(&tp->napi);
                        netif_carrier_on(netdev);
                        rtl_start_rx(tp);
+                       napi_enable(&tp->napi);
                }
        } else {
                if (netif_carrier_ok(netdev)) {
@@ -3251,6 +3270,7 @@ static void r8153_init(struct r8152 *tp)
                msleep(20);
        }
 
+       usb_disable_lpm(tp->udev);
        r8153_u2p3en(tp, false);
 
        if (tp->version == RTL_VER_04) {
@@ -3318,6 +3338,59 @@ static void r8153_init(struct r8152 *tp)
        r8153_enable_aldps(tp);
        r8152b_enable_fc(tp);
        rtl_tally_reset(tp);
+       r8153_u2p3en(tp, true);
+}
+
+static int rtl8152_pre_reset(struct usb_interface *intf)
+{
+       struct r8152 *tp = usb_get_intfdata(intf);
+       struct net_device *netdev;
+
+       if (!tp)
+               return 0;
+
+       netdev = tp->netdev;
+       if (!netif_running(netdev))
+               return 0;
+
+       napi_disable(&tp->napi);
+       clear_bit(WORK_ENABLE, &tp->flags);
+       usb_kill_urb(tp->intr_urb);
+       cancel_delayed_work_sync(&tp->schedule);
+       if (netif_carrier_ok(netdev)) {
+               netif_stop_queue(netdev);
+               mutex_lock(&tp->control);
+               tp->rtl_ops.disable(tp);
+               mutex_unlock(&tp->control);
+       }
+
+       return 0;
+}
+
+static int rtl8152_post_reset(struct usb_interface *intf)
+{
+       struct r8152 *tp = usb_get_intfdata(intf);
+       struct net_device *netdev;
+
+       if (!tp)
+               return 0;
+
+       netdev = tp->netdev;
+       if (!netif_running(netdev))
+               return 0;
+
+       set_bit(WORK_ENABLE, &tp->flags);
+       if (netif_carrier_ok(netdev)) {
+               mutex_lock(&tp->control);
+               tp->rtl_ops.enable(tp);
+               rtl8152_set_rx_mode(netdev);
+               mutex_unlock(&tp->control);
+               netif_wake_queue(netdev);
+       }
+
+       napi_enable(&tp->napi);
+
+       return 0;
 }
 
 static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
@@ -3373,9 +3446,11 @@ static int rtl8152_resume(struct usb_interface *intf)
                if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
                        rtl_runtime_suspend_enable(tp, false);
                        clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+                       napi_disable(&tp->napi);
                        set_bit(WORK_ENABLE, &tp->flags);
                        if (netif_carrier_ok(tp->netdev))
                                rtl_start_rx(tp);
+                       napi_enable(&tp->napi);
                } else {
                        tp->rtl_ops.up(tp);
                        rtl8152_set_speed(tp, AUTONEG_ENABLE,
@@ -3402,12 +3477,15 @@ static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        if (usb_autopm_get_interface(tp->intf) < 0)
                return;
 
-       mutex_lock(&tp->control);
-
-       wol->supported = WAKE_ANY;
-       wol->wolopts = __rtl_get_wol(tp);
-
-       mutex_unlock(&tp->control);
+       if (!rtl_can_wakeup(tp)) {
+               wol->supported = 0;
+               wol->wolopts = 0;
+       } else {
+               mutex_lock(&tp->control);
+               wol->supported = WAKE_ANY;
+               wol->wolopts = __rtl_get_wol(tp);
+               mutex_unlock(&tp->control);
+       }
 
        usb_autopm_put_interface(tp->intf);
 }
@@ -3417,6 +3495,9 @@ static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct r8152 *tp = netdev_priv(dev);
        int ret;
 
+       if (!rtl_can_wakeup(tp))
+               return -EOPNOTSUPP;
+
        ret = usb_autopm_get_interface(tp->intf);
        if (ret < 0)
                goto out_set_wol;
@@ -4058,6 +4139,9 @@ static int rtl8152_probe(struct usb_interface *intf,
                goto out1;
        }
 
+       if (!rtl_can_wakeup(tp))
+               __rtl_set_wol(tp, 0);
+
        tp->saved_wolopts = __rtl_get_wol(tp);
        if (tp->saved_wolopts)
                device_set_wakeup_enable(&udev->dev, true);
@@ -4117,6 +4201,7 @@ static struct usb_device_id rtl8152_table[] = {
        {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)},
        {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x7205)},
        {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA,  0x09ff)},
        {}
 };
 
@@ -4130,6 +4215,8 @@ static struct usb_driver rtl8152_driver = {
        .suspend =      rtl8152_suspend,
        .resume =       rtl8152_resume,
        .reset_resume = rtl8152_resume,
+       .pre_reset =    rtl8152_pre_reset,
+       .post_reset =   rtl8152_post_reset,
        .supports_autosuspend = 1,
        .disable_hub_initiated_lpm = 1,
 };
index 63c7810e1545a357eda7578af862ed18322de933..237f8e5e493ddaae958684e8ed411c6f7f2363d6 100644 (file)
@@ -1756,9 +1756,9 @@ static int virtnet_probe(struct virtio_device *vdev)
        /* Do we support "hardware" checksums? */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
                /* This opens up the world of extra features. */
-               dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+               dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
                if (csum)
-                       dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+                       dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
 
                if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
                        dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
@@ -1828,7 +1828,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        else
                vi->hdr_len = sizeof(struct virtio_net_hdr);
 
-       if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT))
+       if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT) ||
+           virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
                vi->any_header_sg = true;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
index da11bb5e9c7fb82edd383384fe2fd392b7a1c59d..46f4caddccbed84a56b12aad93a683618401fbdb 100644 (file)
@@ -1216,7 +1216,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
        static const u32 rxprod_reg[2] = {
                VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2
        };
-       u32 num_rxd = 0;
+       u32 num_pkts = 0;
        bool skip_page_frags = false;
        struct Vmxnet3_RxCompDesc *rcd;
        struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
@@ -1235,13 +1235,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                struct Vmxnet3_RxDesc *rxd;
                u32 idx, ring_idx;
                struct vmxnet3_cmd_ring *ring = NULL;
-               if (num_rxd >= quota) {
+               if (num_pkts >= quota) {
                        /* we may stop even before we see the EOP desc of
                         * the current pkt
                         */
                        break;
                }
-               num_rxd++;
                BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
                idx = rcd->rxdIdx;
                ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
@@ -1413,6 +1412,7 @@ not_lro:
                                napi_gro_receive(&rq->napi, skb);
 
                        ctx->skb = NULL;
+                       num_pkts++;
                }
 
 rcd_done:
@@ -1443,7 +1443,7 @@ rcd_done:
                                  &rq->comp_ring.base[rq->comp_ring.next2proc].rcd, &rxComp);
        }
 
-       return num_rxd;
+       return num_pkts;
 }
 
 
index 7193b7304fdd3ed4b69c0125732d4a024d4a4b36..848ea6a399f236b14cc5d9a79dd38038e0331aec 100644 (file)
@@ -589,7 +589,8 @@ static int cosa_probe(int base, int irq, int dma)
                chan->netdev->base_addr = chan->cosa->datareg;
                chan->netdev->irq = chan->cosa->irq;
                chan->netdev->dma = chan->cosa->dma;
-               if (register_hdlc_device(chan->netdev)) {
+               err = register_hdlc_device(chan->netdev);
+               if (err) {
                        netdev_warn(chan->netdev,
                                    "register_hdlc_device() failed\n");
                        free_netdev(chan->netdev);
index feacc3b994b7e621570ab93a6c142eb7aa5e9547..2f0bd6955f3398d65a4a71177fa8bbd56b446825 100644 (file)
@@ -1044,7 +1044,7 @@ EXPORT_SYMBOL(z8530_sync_dma_close);
  *     @dev: The network device to attach
  *     @c: The Z8530 channel to configure in sync DMA mode.
  *
- *     Set up a Z85x30 device for synchronous DMA tranmission. One
+ *     Set up a Z85x30 device for synchronous DMA transmission. One
  *     ISA DMA channel must be available for this to work. The receive
  *     side is run in PIO mode, but then it has the bigger FIFO.
  */
index 5e15e8e10ed39f0b605783176fe260faa387d083..a31a6804dc34eff8174b06e15d8ee14bb5405888 100644 (file)
@@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
                return;
        case AR9300_DEVID_QCA956X:
                ah->hw_version.macVersion = AR_SREV_VERSION_9561;
+               return;
        }
 
        val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
index 25d1cbd34306e03ea4827e09509c345d11b5a1df..b2f0d245bcf3a0e71fb96797c47f71ad0ca736db 100644 (file)
@@ -3728,7 +3728,7 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
                switch (phy->rev) {
                case 6:
                case 5:
-                       if (sprom->fem.ghz5.extpa_gain == 3)
+                       if (sprom->fem.ghz2.extpa_gain == 3)
                                return b43_ntab_tx_gain_epa_rev3_hi_pwr_2g;
                        /* fall through */
                case 4:
index d56064861a9c353dfb9fcf1720e1abde6c3fcf9d..d45dc021cda2c0715b8d7e740ff90b46589ae141 100644 (file)
@@ -438,6 +438,12 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define RX_QUEUE_MASK                         255
 #define RX_QUEUE_SIZE_LOG                     8
 
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
 /**
  * struct iwl_rb_status - reserve buffer status
  *     host memory mapped FH registers
index 80fefe7d7b8cb3b46581b32f299fed425e878980..3b8e85e51002560a0a860db0999ec947c29fb0d2 100644 (file)
@@ -540,13 +540,11 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
                hw_addr = (const u8 *)(mac_override +
                                 MAC_ADDRESS_OVERRIDE_FAMILY_8000);
 
-               /* The byte order is little endian 16 bit, meaning 214365 */
-               data->hw_addr[0] = hw_addr[1];
-               data->hw_addr[1] = hw_addr[0];
-               data->hw_addr[2] = hw_addr[3];
-               data->hw_addr[3] = hw_addr[2];
-               data->hw_addr[4] = hw_addr[5];
-               data->hw_addr[5] = hw_addr[4];
+               /*
+                * Store the MAC address from MAO section.
+                * No byte swapping is required in MAO section
+                */
+               memcpy(data->hw_addr, hw_addr, ETH_ALEN);
 
                /*
                 * Force the use of the OTP MAC address in case of reserved MAC
index 5e4cbdb44c607ec8399bae489f28990dc907eaeb..737774a01c74a500b3934928449531889701d7f5 100644 (file)
@@ -660,7 +660,8 @@ struct iwl_scan_config {
  * iwl_umac_scan_flags
  *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request
  *     can be preempted by other scan requests with higher priority.
- *     The low priority scan is aborted.
+ *     The low priority scan will be resumed when the higher proirity scan is
+ *     completed.
  *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver
  *     when scan starts.
  */
index 5de144968723d4f2a5446f0d6f9fc0607baf2efb..5514ad6d4e54373d2a48564ec790489dfe1808dc 100644 (file)
@@ -1023,7 +1023,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
        cmd->scan_priority =
                iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
 
-       if (iwl_mvm_scan_total_iterations(params) == 0)
+       if (iwl_mvm_scan_total_iterations(params) == 1)
                cmd->ooc_priority =
                        iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
        else
@@ -1109,6 +1109,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        cmd->uid = cpu_to_le32(uid);
        cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params));
 
+       if (type == IWL_MVM_SCAN_SCHED)
+               cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
+
        if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))
                cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
                                     IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
index d68dc697a4a06ef2b9c786de0fc98f3e5fe35544..26f076e821491e09d7805c5f37d229d01480229c 100644 (file)
@@ -1401,6 +1401,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
        u8 sta_id;
        int ret;
+       static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -1467,7 +1468,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
 end:
        IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
                      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
-                     sta->addr, ret);
+                     sta ? sta->addr : zero_addr, ret);
        return ret;
 }
 
index d24b6a83e68cfcd4281301c907cb62a24661da96..e472729e5f149a451fd7128d45fa54856c8a77ce 100644 (file)
@@ -86,7 +86,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
 {
        lockdep_assert_held(&mvm->time_event_lock);
 
-       if (te_data->id == TE_MAX)
+       if (!te_data->vif)
                return;
 
        list_del(&te_data->list);
index 7ba7a118ff5ca28615f5ceeb745f577999ea52dc..89116864d2a0ec346941ec8e4fded14691612ff3 100644 (file)
@@ -252,7 +252,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
 
        if (info->band == IEEE80211_BAND_2GHZ &&
            !iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
-               rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS;
+               rate_flags = mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS;
        else
                rate_flags =
                        BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
index 2ed1e4d2774da83f1cd609983c8383c48d37a128..9f65c1cff1b1958057ab3bedf385604b34a3323e 100644 (file)
@@ -368,12 +368,14 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 /* 3165 Series */
        {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3166, 0x4212, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x8110, iwl3165_2ac_cfg)},
 
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
@@ -426,9 +428,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)},
index 31f72a61cc3fe06b6d9189f718cc3315677625ad..376b84e54ad7e8bbb48d039d354c03748665451c 100644 (file)
 #include "iwl-io.h"
 #include "iwl-op-mode.h"
 
-/*
- * RX related structures and functions
- */
-#define RX_NUM_QUEUES 1
-#define RX_POST_REQ_ALLOC 2
-#define RX_CLAIM_REQ_ALLOC 8
-#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES)
-#define RX_LOW_WATERMARK 8
-
 struct iwl_host_cmd;
 
 /*This file includes the declaration that are internal to the
@@ -86,29 +77,29 @@ struct isr_statistics {
  * struct iwl_rxq - Rx queue
  * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
  * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @pool:
+ * @queue:
  * @read: Shared index to newest available Rx buffer
  * @write: Shared index to oldest written Rx packet
  * @free_count: Number of pre-allocated buffers in rx_free
- * @used_count: Number of RBDs handled to allocator to use for allocation
  * @write_actual:
- * @rx_free: list of RBDs with allocated RB ready for use
- * @rx_used: list of RBDs with no RB attached
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
  * @need_update: flag to indicate we need to update read/write index
  * @rb_stts: driver's pointer to receive buffer status
  * @rb_stts_dma: bus address of receive buffer status
  * @lock:
- * @pool: initial pool of iwl_rx_mem_buffer for the queue
- * @queue: actual rx queue
  *
  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
 struct iwl_rxq {
        __le32 *bd;
        dma_addr_t bd_dma;
+       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
        u32 read;
        u32 write;
        u32 free_count;
-       u32 used_count;
        u32 write_actual;
        struct list_head rx_free;
        struct list_head rx_used;
@@ -116,32 +107,6 @@ struct iwl_rxq {
        struct iwl_rb_status *rb_stts;
        dma_addr_t rb_stts_dma;
        spinlock_t lock;
-       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE];
-       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
-};
-
-/**
- * struct iwl_rb_allocator - Rx allocator
- * @pool: initial pool of allocator
- * @req_pending: number of requests the allcator had not processed yet
- * @req_ready: number of requests honored and ready for claiming
- * @rbd_allocated: RBDs with pages allocated and ready to be handled to
- *     the queue. This is a list of &struct iwl_rx_mem_buffer
- * @rbd_empty: RBDs with no page attached for allocator use. This is a list
- *     of &struct iwl_rx_mem_buffer
- * @lock: protects the rbd_allocated and rbd_empty lists
- * @alloc_wq: work queue for background calls
- * @rx_alloc: work struct for background calls
- */
-struct iwl_rb_allocator {
-       struct iwl_rx_mem_buffer pool[RX_POOL_SIZE];
-       atomic_t req_pending;
-       atomic_t req_ready;
-       struct list_head rbd_allocated;
-       struct list_head rbd_empty;
-       spinlock_t lock;
-       struct workqueue_struct *alloc_wq;
-       struct work_struct rx_alloc;
 };
 
 struct iwl_dma_ptr {
@@ -285,7 +250,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
 /**
  * struct iwl_trans_pcie - PCIe transport specific data
  * @rxq: all the RX queue data
- * @rba: allocator for RX replenishing
+ * @rx_replenish: work that will be called when buffers need to be allocated
  * @drv - pointer to iwl_drv
  * @trans: pointer to the generic transport area
  * @scd_base_addr: scheduler sram base address in SRAM
@@ -308,7 +273,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  */
 struct iwl_trans_pcie {
        struct iwl_rxq rxq;
-       struct iwl_rb_allocator rba;
+       struct work_struct rx_replenish;
        struct iwl_trans *trans;
        struct iwl_drv *drv;
 
index a3fbaa0ef5e04de7d1032c79ca35e82364dac7ea..adad8d0fae7f2766812826377c46d29f1f77d4ed 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
  * resets the Rx queue buffers with new memory.
  *
  * The management in the driver is as follows:
- * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free.
- *   When the interrupt handler is called, the request is processed.
- *   The page is either stolen - transferred to the upper layer
- *   or reused - added immediately to the iwl->rxq->rx_free list.
- * + When the page is stolen - the driver updates the matching queue's used
- *   count, detaches the RBD and transfers it to the queue used list.
- *   When there are two used RBDs - they are transferred to the allocator empty
- *   list. Work is then scheduled for the allocator to start allocating
- *   eight buffers.
- *   When there are another 6 used RBDs - they are transferred to the allocator
- *   empty list and the driver tries to claim the pre-allocated buffers and
- *   add them to iwl->rxq->rx_free. If it fails - it continues to claim them
- *   until ready.
- *   When there are 8+ buffers in the free list - either from allocation or from
- *   8 reused unstolen pages - restock is called to update the FW and indexes.
- * + In order to make sure the allocator always has RBDs to use for allocation
- *   the allocator has initial pool in the size of num_queues*(8-2) - the
- *   maximum missing RBDs per allocation request (request posted with 2
- *    empty RBDs, there is no guarantee when the other 6 RBDs are supplied).
- *   The queues supplies the recycle of the rest of the RBDs.
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
  *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + If there are no allocated buffers in iwl->rxq->rx_free,
+ * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
+ *   rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
  *   the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
  *   If there were enough free buffers and RX_STALLED is set it is cleared.
  *
  *
  * iwl_rxq_alloc()            Allocates rx_free
  * iwl_pcie_rx_replenish()    Replenishes rx_free list from rx_used, and calls
- *                            iwl_pcie_rxq_restock.
- *                            Used only during initialization.
+ *                            iwl_pcie_rxq_restock
  * iwl_pcie_rxq_restock()     Moves available buffers from rx_free into Rx
  *                            queue, updates firmware pointers, and updates
- *                            the WRITE index.
- * iwl_pcie_rx_allocator()     Background work for allocating pages.
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_pcie_rx_replenish
  *
  * -- enable interrupts --
  * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
  *                            READ INDEX, detaching the SKB from the pool.
  *                            Moves the packet buffer from queue to rx_used.
- *                            Posts and claims requests to the allocator.
  *                            Calls iwl_pcie_rxq_restock to refill any empty
  *                            slots.
- *
- * RBD life-cycle:
- *
- * Init:
- * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue
- *
- * Regular Receive interrupt:
- * Page Stolen:
- * rxq.queue -> rxq.rx_used -> allocator.rbd_empty ->
- * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue
- * Page not Stolen:
- * rxq.queue -> rxq.rx_free -> rxq.queue
  * ...
  *
  */
@@ -267,6 +240,10 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
                rxq->free_count--;
        }
        spin_unlock(&rxq->lock);
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               schedule_work(&trans_pcie->rx_replenish);
 
        /* If we've added more space for the firmware to place data, tell it.
         * Increment device's write pointer in multiples of 8. */
@@ -277,44 +254,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        }
 }
 
-/*
- * iwl_pcie_rx_alloc_page - allocates and returns a page.
- *
- */
-static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct page *page;
-       gfp_t gfp_mask = GFP_KERNEL;
-
-       if (rxq->free_count > RX_LOW_WATERMARK)
-               gfp_mask |= __GFP_NOWARN;
-
-       if (trans_pcie->rx_page_order > 0)
-               gfp_mask |= __GFP_COMP;
-
-       /* Alloc a new receive buffer */
-       page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
-       if (!page) {
-               if (net_ratelimit())
-                       IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n",
-                                      trans_pcie->rx_page_order);
-               /* Issue an error if the hardware has consumed more than half
-                * of its free buffer list and we don't have enough
-                * pre-allocated buffers.
-`               */
-               if (rxq->free_count <= RX_LOW_WATERMARK &&
-                   iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) &&
-                   net_ratelimit())
-                       IWL_CRIT(trans,
-                                "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n",
-                                rxq->free_count);
-               return NULL;
-       }
-       return page;
-}
-
 /*
  * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD
  *
@@ -324,12 +263,13 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans)
  * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
  * allocated buffers.
  */
-static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
+       gfp_t gfp_mask = priority;
 
        while (1) {
                spin_lock(&rxq->lock);
@@ -339,10 +279,32 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans)
                }
                spin_unlock(&rxq->lock);
 
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
+
+               if (trans_pcie->rx_page_order > 0)
+                       gfp_mask |= __GFP_COMP;
+
                /* Alloc a new receive buffer */
-               page = iwl_pcie_rx_alloc_page(trans);
-               if (!page)
+               page = alloc_pages(gfp_mask, trans_pcie->rx_page_order);
+               if (!page) {
+                       if (net_ratelimit())
+                               IWL_DEBUG_INFO(trans, "alloc_pages failed, "
+                                          "order: %d\n",
+                                          trans_pcie->rx_page_order);
+
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(trans, "Failed to alloc_pages with %s."
+                                        "Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?
+                                        "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
+                       /* We don't reschedule replenish work here -- we will
+                        * call the restock method and if it still needs
+                        * more buffers it will schedule replenish */
                        return;
+               }
 
                spin_lock(&rxq->lock);
 
@@ -393,7 +355,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
 
        lockdep_assert_held(&rxq->lock);
 
-       for (i = 0; i < RX_QUEUE_SIZE; i++) {
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
                if (!rxq->pool[i].page)
                        continue;
                dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
@@ -410,144 +372,32 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
  * When moving to rx_free an page is allocated for the slot.
  *
  * Also restock the Rx queue via iwl_pcie_rxq_restock.
- * This is called only during initialization
+ * This is called as a scheduled work item (except for during initialization)
  */
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
+static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp)
 {
-       iwl_pcie_rxq_alloc_rbs(trans);
+       iwl_pcie_rxq_alloc_rbs(trans, gfp);
 
        iwl_pcie_rxq_restock(trans);
 }
 
-/*
- * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues
- *
- * Allocates for each received request 8 pages
- * Called as a scheduled work item.
- */
-static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-
-       while (atomic_read(&rba->req_pending)) {
-               int i;
-               struct list_head local_empty;
-               struct list_head local_allocated;
-
-               INIT_LIST_HEAD(&local_allocated);
-               spin_lock(&rba->lock);
-               /* swap out the entire rba->rbd_empty to a local list */
-               list_replace_init(&rba->rbd_empty, &local_empty);
-               spin_unlock(&rba->lock);
-
-               for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {
-                       struct iwl_rx_mem_buffer *rxb;
-                       struct page *page;
-
-                       /* List should never be empty - each reused RBD is
-                        * returned to the list, and initial pool covers any
-                        * possible gap between the time the page is allocated
-                        * to the time the RBD is added.
-                        */
-                       BUG_ON(list_empty(&local_empty));
-                       /* Get the first rxb from the rbd list */
-                       rxb = list_first_entry(&local_empty,
-                                              struct iwl_rx_mem_buffer, list);
-                       BUG_ON(rxb->page);
-
-                       /* Alloc a new receive buffer */
-                       page = iwl_pcie_rx_alloc_page(trans);
-                       if (!page)
-                               continue;
-                       rxb->page = page;
-
-                       /* Get physical address of the RB */
-                       rxb->page_dma = dma_map_page(trans->dev, page, 0,
-                                       PAGE_SIZE << trans_pcie->rx_page_order,
-                                       DMA_FROM_DEVICE);
-                       if (dma_mapping_error(trans->dev, rxb->page_dma)) {
-                               rxb->page = NULL;
-                               __free_pages(page, trans_pcie->rx_page_order);
-                               continue;
-                       }
-                       /* dma address must be no more than 36 bits */
-                       BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-                       /* and also 256 byte aligned! */
-                       BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-                       /* move the allocated entry to the out list */
-                       list_move(&rxb->list, &local_allocated);
-                       i++;
-               }
-
-               spin_lock(&rba->lock);
-               /* add the allocated rbds to the allocator allocated list */
-               list_splice_tail(&local_allocated, &rba->rbd_allocated);
-               /* add the unused rbds back to the allocator empty list */
-               list_splice_tail(&local_empty, &rba->rbd_empty);
-               spin_unlock(&rba->lock);
-
-               atomic_dec(&rba->req_pending);
-               atomic_inc(&rba->req_ready);
-       }
-}
-
-/*
- * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages
-.*
-.* Called by queue when the queue posted allocation request and
- * has freed 8 RBDs in order to restock itself.
- */
-static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans,
-                                    struct iwl_rx_mem_buffer
-                                    *out[RX_CLAIM_REQ_ALLOC])
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i;
-
-       if (atomic_dec_return(&rba->req_ready) < 0) {
-               atomic_inc(&rba->req_ready);
-               IWL_DEBUG_RX(trans,
-                            "Allocation request not ready, pending requests = %d\n",
-                            atomic_read(&rba->req_pending));
-               return -ENOMEM;
-       }
-
-       spin_lock(&rba->lock);
-       for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) {
-               /* Get next free Rx buffer, remove it from free list */
-               out[i] = list_first_entry(&rba->rbd_allocated,
-                              struct iwl_rx_mem_buffer, list);
-               list_del(&out[i]->list);
-       }
-       spin_unlock(&rba->lock);
-
-       return 0;
-}
-
-static void iwl_pcie_rx_allocator_work(struct work_struct *data)
+static void iwl_pcie_rx_replenish_work(struct work_struct *data)
 {
-       struct iwl_rb_allocator *rba_p =
-               container_of(data, struct iwl_rb_allocator, rx_alloc);
        struct iwl_trans_pcie *trans_pcie =
-               container_of(rba_p, struct iwl_trans_pcie, rba);
+           container_of(data, struct iwl_trans_pcie, rx_replenish);
 
-       iwl_pcie_rx_allocator(trans_pcie->trans);
+       iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL);
 }
 
 static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
        struct device *dev = trans->dev;
 
        memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
 
        spin_lock_init(&rxq->lock);
-       spin_lock_init(&rba->lock);
 
        if (WARN_ON(rxq->bd || rxq->rb_stts))
                return -EINVAL;
@@ -637,49 +487,15 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
        INIT_LIST_HEAD(&rxq->rx_free);
        INIT_LIST_HEAD(&rxq->rx_used);
        rxq->free_count = 0;
-       rxq->used_count = 0;
 
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
                list_add(&rxq->pool[i].list, &rxq->rx_used);
 }
 
-static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba)
-{
-       int i;
-
-       lockdep_assert_held(&rba->lock);
-
-       INIT_LIST_HEAD(&rba->rbd_allocated);
-       INIT_LIST_HEAD(&rba->rbd_empty);
-
-       for (i = 0; i < RX_POOL_SIZE; i++)
-               list_add(&rba->pool[i].list, &rba->rbd_empty);
-}
-
-static void iwl_pcie_rx_free_rba(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i;
-
-       lockdep_assert_held(&rba->lock);
-
-       for (i = 0; i < RX_POOL_SIZE; i++) {
-               if (!rba->pool[i].page)
-                       continue;
-               dma_unmap_page(trans->dev, rba->pool[i].page_dma,
-                              PAGE_SIZE << trans_pcie->rx_page_order,
-                              DMA_FROM_DEVICE);
-               __free_pages(rba->pool[i].page, trans_pcie->rx_page_order);
-               rba->pool[i].page = NULL;
-       }
-}
-
 int iwl_pcie_rx_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
        int i, err;
 
        if (!rxq->bd) {
@@ -687,21 +503,11 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
                if (err)
                        return err;
        }
-       if (!rba->alloc_wq)
-               rba->alloc_wq = alloc_workqueue("rb_allocator",
-                                               WQ_HIGHPRI | WQ_UNBOUND, 1);
-       INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work);
-
-       spin_lock(&rba->lock);
-       atomic_set(&rba->req_pending, 0);
-       atomic_set(&rba->req_ready, 0);
-       /* free all first - we might be reconfigured for a different size */
-       iwl_pcie_rx_free_rba(trans);
-       iwl_pcie_rx_init_rba(rba);
-       spin_unlock(&rba->lock);
 
        spin_lock(&rxq->lock);
 
+       INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work);
+
        /* free all first - we might be reconfigured for a different size */
        iwl_pcie_rxq_free_rbs(trans);
        iwl_pcie_rx_init_rxb_lists(rxq);
@@ -716,7 +522,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
        spin_unlock(&rxq->lock);
 
-       iwl_pcie_rx_replenish(trans);
+       iwl_pcie_rx_replenish(trans, GFP_KERNEL);
 
        iwl_pcie_rx_hw_init(trans, rxq);
 
@@ -731,7 +537,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
 
        /*if rxq->bd is NULL, it means that nothing has been allocated,
         * exit now */
@@ -740,15 +545,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
                return;
        }
 
-       cancel_work_sync(&rba->rx_alloc);
-       if (rba->alloc_wq) {
-               destroy_workqueue(rba->alloc_wq);
-               rba->alloc_wq = NULL;
-       }
-
-       spin_lock(&rba->lock);
-       iwl_pcie_rx_free_rba(trans);
-       spin_unlock(&rba->lock);
+       cancel_work_sync(&trans_pcie->rx_replenish);
 
        spin_lock(&rxq->lock);
        iwl_pcie_rxq_free_rbs(trans);
@@ -769,43 +566,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
        rxq->rb_stts = NULL;
 }
 
-/*
- * iwl_pcie_rx_reuse_rbd - Recycle used RBDs
- *
- * Called when a RBD can be reused. The RBD is transferred to the allocator.
- * When there are 2 empty RBDs - a request for allocation is posted
- */
-static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
-                                 struct iwl_rx_mem_buffer *rxb,
-                                 struct iwl_rxq *rxq)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-
-       /* Count the used RBDs */
-       rxq->used_count++;
-
-       /* Move the RBD to the used list, will be moved to allocator in batches
-        * before claiming or posting a request*/
-       list_add_tail(&rxb->list, &rxq->rx_used);
-
-       /* If we have RX_POST_REQ_ALLOC new released rx buffers -
-        * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is
-        * used for the case we failed to claim RX_CLAIM_REQ_ALLOC,
-        * after but we still need to post another request.
-        */
-       if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) {
-               /* Move the 2 RBDs to the allocator ownership.
-                Allocator has another 6 from pool for the request completion*/
-               spin_lock(&rba->lock);
-               list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
-               spin_unlock(&rba->lock);
-
-               atomic_inc(&rba->req_pending);
-               queue_work(rba->alloc_wq, &rba->rx_alloc);
-       }
-}
-
 static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                                struct iwl_rx_mem_buffer *rxb)
 {
@@ -928,13 +688,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                         */
                        __free_pages(rxb->page, trans_pcie->rx_page_order);
                        rxb->page = NULL;
-                       iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
+                       list_add_tail(&rxb->list, &rxq->rx_used);
                } else {
                        list_add_tail(&rxb->list, &rxq->rx_free);
                        rxq->free_count++;
                }
        } else
-               iwl_pcie_rx_reuse_rbd(trans, rxb, rxq);
+               list_add_tail(&rxb->list, &rxq->rx_used);
 }
 
 /*
@@ -944,7 +704,10 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       u32 r, i, j;
+       u32 r, i;
+       u8 fill_rx = 0;
+       u32 count = 8;
+       int total_empty;
 
 restart:
        spin_lock(&rxq->lock);
@@ -957,6 +720,14 @@ restart:
        if (i == r)
                IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
 
+       /* calculate total frames need to be restock after handling RX */
+       total_empty = r - rxq->write_actual;
+       if (total_empty < 0)
+               total_empty += RX_QUEUE_SIZE;
+
+       if (total_empty > (RX_QUEUE_SIZE / 2))
+               fill_rx = 1;
+
        while (i != r) {
                struct iwl_rx_mem_buffer *rxb;
 
@@ -968,48 +739,29 @@ restart:
                iwl_pcie_rx_handle_rb(trans, rxb);
 
                i = (i + 1) & RX_QUEUE_MASK;
-
-               /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
-                * try to claim the pre-allocated buffers from the allocator */
-               if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) {
-                       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-                       struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC];
-
-                       /* Add the remaining 6 empty RBDs for allocator use */
-                       spin_lock(&rba->lock);
-                       list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty);
-                       spin_unlock(&rba->lock);
-
-                       /* If not ready - continue, will try to reclaim later.
-                       * No need to reschedule work - allocator exits only on
-                       * success */
-                       if (!iwl_pcie_rx_allocator_get(trans, out)) {
-                               /* If success - then RX_CLAIM_REQ_ALLOC
-                                * buffers were retrieved and should be added
-                                * to free list */
-                               rxq->used_count -= RX_CLAIM_REQ_ALLOC;
-                               for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) {
-                                       list_add_tail(&out[j]->list,
-                                                     &rxq->rx_free);
-                                       rxq->free_count++;
-                               }
+               /* If there are a lot of unused frames,
+                * restock the Rx queue so ucode wont assert. */
+               if (fill_rx) {
+                       count++;
+                       if (count >= 8) {
+                               rxq->read = i;
+                               spin_unlock(&rxq->lock);
+                               iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
+                               count = 0;
+                               goto restart;
                        }
                }
-               /* handle restock for two cases:
-               * - we just pulled buffers from the allocator
-               * - we have 8+ unstolen pages accumulated */
-               if (rxq->free_count >=  RX_CLAIM_REQ_ALLOC) {
-                       rxq->read = i;
-                       spin_unlock(&rxq->lock);
-                       iwl_pcie_rxq_restock(trans);
-                       goto restart;
-               }
        }
 
        /* Backtrack one entry */
        rxq->read = i;
        spin_unlock(&rxq->lock);
 
+       if (fill_rx)
+               iwl_pcie_rx_replenish(trans, GFP_ATOMIC);
+       else
+               iwl_pcie_rxq_restock(trans);
+
        if (trans_pcie->napi.poll)
                napi_gro_flush(&trans_pcie->napi, false);
 }
index 43ae658af6ec56506f9f0e8ed00022b890c3b9fb..9e144e71da0b5980264702a6210684cfa34edab5 100644 (file)
@@ -182,7 +182,7 @@ static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val)
 
 static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 {
-       if (!trans->cfg->apmg_not_supported)
+       if (trans->cfg->apmg_not_supported)
                return;
 
        if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
@@ -478,10 +478,16 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
                if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
                        iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
                                          APMG_PCIDEV_STT_VAL_WAKE_ME);
-               else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+               else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
+                       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                                   CSR_RESET_LINK_PWR_MGMT_DISABLED);
                        iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                                    CSR_HW_IF_CONFIG_REG_PREPARE |
                                    CSR_HW_IF_CONFIG_REG_ENABLE_PME);
+                       mdelay(1);
+                       iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                                     CSR_RESET_LINK_PWR_MGMT_DISABLED);
+               }
                mdelay(5);
        }
 
@@ -575,6 +581,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
        if (ret >= 0)
                return 0;
 
+       iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                   CSR_RESET_LINK_PWR_MGMT_DISABLED);
+       msleep(1);
+
        for (iter = 0; iter < 10; iter++) {
                /* If HW is not ready, prepare the conditions to check again */
                iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
@@ -582,8 +592,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
 
                do {
                        ret = iwl_pcie_set_hw_ready(trans);
-                       if (ret >= 0)
-                               return 0;
+                       if (ret >= 0) {
+                               ret = 0;
+                               goto out;
+                       }
 
                        usleep_range(200, 1000);
                        t += 200;
@@ -593,6 +605,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
 
        IWL_ERR(trans, "Couldn't prepare the card\n");
 
+out:
+       iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
+                     CSR_RESET_LINK_PWR_MGMT_DISABLED);
+
        return ret;
 }
 
@@ -2459,7 +2475,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        struct iwl_trans_pcie *trans_pcie;
        struct iwl_trans *trans;
        u16 pci_cmd;
-       int err;
+       int ret;
 
        trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
                                &pdev->dev, cfg, &trans_ops_pcie, 0);
@@ -2474,8 +2490,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        spin_lock_init(&trans_pcie->ref_lock);
        init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
-       err = pci_enable_device(pdev);
-       if (err)
+       ret = pci_enable_device(pdev);
+       if (ret)
                goto out_no_pci;
 
        if (!cfg->base_params->pcie_l1_allowed) {
@@ -2491,23 +2507,23 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 
        pci_set_master(pdev);
 
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
-       if (!err)
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
-       if (err) {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (!err)
-                       err = pci_set_consistent_dma_mask(pdev,
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (!ret)
+               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+       if (ret) {
+               ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (!ret)
+                       ret = pci_set_consistent_dma_mask(pdev,
                                                          DMA_BIT_MASK(32));
                /* both attempts failed: */
-               if (err) {
+               if (ret) {
                        dev_err(&pdev->dev, "No suitable DMA available\n");
                        goto out_pci_disable_device;
                }
        }
 
-       err = pci_request_regions(pdev, DRV_NAME);
-       if (err) {
+       ret = pci_request_regions(pdev, DRV_NAME);
+       if (ret) {
                dev_err(&pdev->dev, "pci_request_regions failed\n");
                goto out_pci_disable_device;
        }
@@ -2515,7 +2531,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
        if (!trans_pcie->hw_base) {
                dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
-               err = -ENODEV;
+               ret = -ENODEV;
                goto out_pci_release_regions;
        }
 
@@ -2527,9 +2543,9 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        trans_pcie->pci_dev = pdev;
        iwl_disable_interrupts(trans);
 
-       err = pci_enable_msi(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err);
+       ret = pci_enable_msi(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret);
                /* enable rfkill interrupt: hw bug w/a */
                pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
                if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
@@ -2547,11 +2563,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
         */
        if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
                unsigned long flags;
-               int ret;
 
                trans->hw_rev = (trans->hw_rev & 0xfff0) |
                                (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2);
 
+               ret = iwl_pcie_prepare_card_hw(trans);
+               if (ret) {
+                       IWL_WARN(trans, "Exit HW not ready\n");
+                       goto out_pci_disable_msi;
+               }
+
                /*
                 * in-order to recognize C step driver should read chip version
                 * id located at the AUX bus MISC address space.
@@ -2591,13 +2612,14 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        /* Initialize the wait queue for commands */
        init_waitqueue_head(&trans_pcie->wait_command_queue);
 
-       if (iwl_pcie_alloc_ict(trans))
+       ret = iwl_pcie_alloc_ict(trans);
+       if (ret)
                goto out_pci_disable_msi;
 
-       err = request_threaded_irq(pdev->irq, iwl_pcie_isr,
+       ret = request_threaded_irq(pdev->irq, iwl_pcie_isr,
                                   iwl_pcie_irq_handler,
                                   IRQF_SHARED, DRV_NAME, trans);
-       if (err) {
+       if (ret) {
                IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
                goto out_free_ict;
        }
@@ -2617,5 +2639,5 @@ out_pci_disable_device:
        pci_disable_device(pdev);
 out_no_pci:
        iwl_trans_free(trans);
-       return ERR_PTR(err);
+       return ERR_PTR(ret);
 }
index 2b86c2135de36f627b397add88628bc47aa37271..607acb53c847558793d47a528d0830f9c79c8cbf 100644 (file)
@@ -1875,8 +1875,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
        /* start timer if queue currently empty */
        if (q->read_ptr == q->write_ptr) {
-               if (txq->wd_timeout)
-                       mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
+               if (txq->wd_timeout) {
+                       /*
+                        * If the TXQ is active, then set the timer, if not,
+                        * set the timer in remainder so that the timer will
+                        * be armed with the right value when the station will
+                        * wake up.
+                        */
+                       if (!txq->frozen)
+                               mod_timer(&txq->stuck_timer,
+                                         jiffies + txq->wd_timeout);
+                       else
+                               txq->frozen_expiry_remainder = txq->wd_timeout;
+               }
                IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
                iwl_trans_pcie_ref(trans);
        }
index b6cc9ff47fc2e59b3cc92fe4002f05e59d981e56..1c6788aecc62658fe2cc7c4961415ef4715c8dde 100644 (file)
@@ -172,6 +172,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
                (struct rsi_91x_sdiodev *)adapter->rsi_dev;
        u32 len;
        u32 num_blocks;
+       const u8 *fw;
        const struct firmware *fw_entry = NULL;
        u32 block_size = dev->tx_blk_size;
        int status = 0;
@@ -200,6 +201,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
                return status;
        }
 
+       /* Copy firmware into DMA-accessible memory */
+       fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+       if (!fw)
+               return -ENOMEM;
        len = fw_entry->size;
 
        if (len % 4)
@@ -210,7 +215,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
        rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
        rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
 
-       status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks);
+       status = rsi_copy_to_card(common, fw, len, num_blocks);
+       kfree(fw);
        release_firmware(fw_entry);
        return status;
 }
index 1106ce76707e1095fd523c5c541fa3740e9c9496..30c2cf7fa93b0c6015d22236c3a9189b462cb064 100644 (file)
@@ -146,7 +146,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
                return status;
        }
 
+       /* Copy firmware into DMA-accessible memory */
        fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
+       if (!fw)
+               return -ENOMEM;
        len = fw_entry->size;
 
        if (len % 4)
@@ -158,6 +161,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
        rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
 
        status = rsi_copy_to_card(common, fw, len, num_blocks);
+       kfree(fw);
        release_firmware(fw_entry);
        return status;
 }
index 3b3a88b53b119909112a806ee71ab4d4bfa67a79..585d0883c7e58760eed503de64ced513c8331c82 100644 (file)
@@ -1015,9 +1015,12 @@ static void send_beacon_frame(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+       struct rtl_tcb_desc tcb_desc;
 
-       if (skb)
-               rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL);
+       if (skb) {
+               memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+               rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc);
+       }
 }
 
 static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
index 1017f02d7bf7520868b25330493822e08f7826a0..7bf88d9dcdc3fc4732170c121ef78d5a85ca3fa9 100644 (file)
@@ -385,6 +385,7 @@ module_param_named(debug, rtl8723be_mod_params.debug, int, 0444);
 module_param_named(ips, rtl8723be_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
+module_param_named(msi, rtl8723be_mod_params.msi_support, bool, 0444);
 module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,
                   bool, 0444);
 MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
index 1a83e190fc15e4158b5e441cc267ad149d465abe..28577a31549d1569032d63457464fe11fdf44d32 100644 (file)
@@ -61,6 +61,12 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue,
 void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue)
 {
        atomic_dec(&queue->inflight_packets);
+
+       /* Wake the dealloc thread _after_ decrementing inflight_packets so
+        * that if kthread_stop() has already been called, the dealloc thread
+        * does not wait forever with nothing to wake it.
+        */
+       wake_up(&queue->dealloc_wq);
 }
 
 int xenvif_schedulable(struct xenvif *vif)
index 880d0d63e872e5725d76fe998db0282c749f45d6..3f44b522b8311a2c64eba48e6a9b7217ea0cb3a7 100644 (file)
@@ -810,23 +810,17 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
 static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *queue,
                                                        struct sk_buff *skb,
                                                        struct xen_netif_tx_request *txp,
-                                                       struct gnttab_map_grant_ref *gop)
+                                                       struct gnttab_map_grant_ref *gop,
+                                                       unsigned int frag_overflow,
+                                                       struct sk_buff *nskb)
 {
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        skb_frag_t *frags = shinfo->frags;
        u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
        int start;
        pending_ring_idx_t index;
-       unsigned int nr_slots, frag_overflow = 0;
+       unsigned int nr_slots;
 
-       /* At this point shinfo->nr_frags is in fact the number of
-        * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
-        */
-       if (shinfo->nr_frags > MAX_SKB_FRAGS) {
-               frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS;
-               BUG_ON(frag_overflow > MAX_SKB_FRAGS);
-               shinfo->nr_frags = MAX_SKB_FRAGS;
-       }
        nr_slots = shinfo->nr_frags;
 
        /* Skip first skb fragment if it is on same page as header fragment. */
@@ -841,13 +835,6 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que
        }
 
        if (frag_overflow) {
-               struct sk_buff *nskb = xenvif_alloc_skb(0);
-               if (unlikely(nskb == NULL)) {
-                       if (net_ratelimit())
-                               netdev_err(queue->vif->dev,
-                                          "Can't allocate the frag_list skb.\n");
-                       return NULL;
-               }
 
                shinfo = skb_shinfo(nskb);
                frags = shinfo->frags;
@@ -1175,9 +1162,10 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                                     unsigned *copy_ops,
                                     unsigned *map_ops)
 {
-       struct gnttab_map_grant_ref *gop = queue->tx_map_ops, *request_gop;
-       struct sk_buff *skb;
+       struct gnttab_map_grant_ref *gop = queue->tx_map_ops;
+       struct sk_buff *skb, *nskb;
        int ret;
+       unsigned int frag_overflow;
 
        while (skb_queue_len(&queue->tx_queue) < budget) {
                struct xen_netif_tx_request txreq;
@@ -1265,6 +1253,29 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        break;
                }
 
+               skb_shinfo(skb)->nr_frags = ret;
+               if (data_len < txreq.size)
+                       skb_shinfo(skb)->nr_frags++;
+               /* At this point shinfo->nr_frags is in fact the number of
+                * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
+                */
+               frag_overflow = 0;
+               nskb = NULL;
+               if (skb_shinfo(skb)->nr_frags > MAX_SKB_FRAGS) {
+                       frag_overflow = skb_shinfo(skb)->nr_frags - MAX_SKB_FRAGS;
+                       BUG_ON(frag_overflow > MAX_SKB_FRAGS);
+                       skb_shinfo(skb)->nr_frags = MAX_SKB_FRAGS;
+                       nskb = xenvif_alloc_skb(0);
+                       if (unlikely(nskb == NULL)) {
+                               kfree_skb(skb);
+                               xenvif_tx_err(queue, &txreq, idx);
+                               if (net_ratelimit())
+                                       netdev_err(queue->vif->dev,
+                                                  "Can't allocate the frag_list skb.\n");
+                               break;
+                       }
+               }
+
                if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
                        struct xen_netif_extra_info *gso;
                        gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
@@ -1272,6 +1283,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        if (xenvif_set_skb_gso(queue->vif, skb, gso)) {
                                /* Failure in xenvif_set_skb_gso is fatal. */
                                kfree_skb(skb);
+                               kfree_skb(nskb);
                                break;
                        }
                }
@@ -1294,9 +1306,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                (*copy_ops)++;
 
-               skb_shinfo(skb)->nr_frags = ret;
                if (data_len < txreq.size) {
-                       skb_shinfo(skb)->nr_frags++;
                        frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
                                             pending_idx);
                        xenvif_tx_create_map_op(queue, pending_idx, &txreq, gop);
@@ -1310,13 +1320,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
 
                queue->pending_cons++;
 
-               request_gop = xenvif_get_requests(queue, skb, txfrags, gop);
-               if (request_gop == NULL) {
-                       kfree_skb(skb);
-                       xenvif_tx_err(queue, &txreq, idx);
-                       break;
-               }
-               gop = request_gop;
+               gop = xenvif_get_requests(queue, skb, txfrags, gop,
+                                         frag_overflow, nskb);
 
                __skb_queue_tail(&queue->tx_queue, skb);
 
@@ -1536,7 +1541,6 @@ void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
                smp_wmb();
                queue->dealloc_prod++;
        } while (ubuf);
-       wake_up(&queue->dealloc_wq);
        spin_unlock_irqrestore(&queue->callback_lock, flags);
 
        if (likely(zerocopy_success))
@@ -1566,13 +1570,13 @@ static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue)
                smp_rmb();
 
                while (dc != dp) {
-                       BUG_ON(gop - queue->tx_unmap_ops > MAX_PENDING_REQS);
+                       BUG_ON(gop - queue->tx_unmap_ops >= MAX_PENDING_REQS);
                        pending_idx =
                                queue->dealloc_ring[pending_index(dc++)];
 
-                       pending_idx_release[gop-queue->tx_unmap_ops] =
+                       pending_idx_release[gop - queue->tx_unmap_ops] =
                                pending_idx;
-                       queue->pages_to_unmap[gop-queue->tx_unmap_ops] =
+                       queue->pages_to_unmap[gop - queue->tx_unmap_ops] =
                                queue->mmap_pages[pending_idx];
                        gnttab_set_unmap_op(gop,
                                            idx_to_kaddr(queue, pending_idx),
index 23435f2a5486f806ee8f686fdb898d0815a68013..2e2530743831a19f2ca4db3b313d1f8b2db44ebb 100644 (file)
@@ -114,7 +114,7 @@ int ntb_register_device(struct ntb_dev *ntb)
        ntb->dev.bus = &ntb_bus;
        ntb->dev.parent = &ntb->pdev->dev;
        ntb->dev.release = ntb_dev_release;
-       dev_set_name(&ntb->dev, pci_name(ntb->pdev));
+       dev_set_name(&ntb->dev, "%s", pci_name(ntb->pdev));
 
        ntb->ctx = NULL;
        ntb->ctx_ops = NULL;
index efe3ad4122f2ee1094da78c1bb31d86642b5b3a6..1c6386d5f79c742737e4ee1a8a2b99df686ffaa0 100644 (file)
@@ -142,10 +142,11 @@ struct ntb_transport_qp {
 
        void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
                           void *data, int len);
+       struct list_head rx_post_q;
        struct list_head rx_pend_q;
        struct list_head rx_free_q;
-       spinlock_t ntb_rx_pend_q_lock;
-       spinlock_t ntb_rx_free_q_lock;
+       /* ntb_rx_q_lock: synchronize access to rx_XXXX_q */
+       spinlock_t ntb_rx_q_lock;
        void *rx_buff;
        unsigned int rx_index;
        unsigned int rx_max_entry;
@@ -211,6 +212,8 @@ struct ntb_transport_ctx {
        bool link_is_up;
        struct delayed_work link_work;
        struct work_struct link_cleanup;
+
+       struct dentry *debugfs_node_dir;
 };
 
 enum {
@@ -436,13 +439,17 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
        char *buf;
        ssize_t ret, out_offset, out_count;
 
+       qp = filp->private_data;
+
+       if (!qp || !qp->link_is_up)
+               return 0;
+
        out_count = 1000;
 
        buf = kmalloc(out_count, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       qp = filp->private_data;
        out_offset = 0;
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "NTB QP stats\n");
@@ -534,6 +541,27 @@ out:
        return entry;
 }
 
+static struct ntb_queue_entry *ntb_list_mv(spinlock_t *lock,
+                                          struct list_head *list,
+                                          struct list_head *to_list)
+{
+       struct ntb_queue_entry *entry;
+       unsigned long flags;
+
+       spin_lock_irqsave(lock, flags);
+
+       if (list_empty(list)) {
+               entry = NULL;
+       } else {
+               entry = list_first_entry(list, struct ntb_queue_entry, entry);
+               list_move_tail(&entry->entry, to_list);
+       }
+
+       spin_unlock_irqrestore(lock, flags);
+
+       return entry;
+}
+
 static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt,
                                     unsigned int qp_num)
 {
@@ -601,13 +629,16 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
 }
 
 static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
-                     unsigned int size)
+                     resource_size_t size)
 {
        struct ntb_transport_mw *mw = &nt->mw_vec[num_mw];
        struct pci_dev *pdev = nt->ndev->pdev;
-       unsigned int xlat_size, buff_size;
+       size_t xlat_size, buff_size;
        int rc;
 
+       if (!size)
+               return -EINVAL;
+
        xlat_size = round_up(size, mw->xlat_align_size);
        buff_size = round_up(size, mw->xlat_align);
 
@@ -627,7 +658,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
        if (!mw->virt_addr) {
                mw->xlat_size = 0;
                mw->buff_size = 0;
-               dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n",
+               dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
                        buff_size);
                return -ENOMEM;
        }
@@ -867,6 +898,8 @@ static void ntb_qp_link_work(struct work_struct *work)
 
                if (qp->event_handler)
                        qp->event_handler(qp->cb_data, qp->link_is_up);
+
+               tasklet_schedule(&qp->rxc_db_work);
        } else if (nt->link_is_up)
                schedule_delayed_work(&qp->link_work,
                                      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
@@ -923,12 +956,12 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
        qp->tx_max_frame = min(transport_mtu, tx_size / 2);
        qp->tx_max_entry = tx_size / qp->tx_max_frame;
 
-       if (nt_debugfs_dir) {
+       if (nt->debugfs_node_dir) {
                char debugfs_name[4];
 
                snprintf(debugfs_name, 4, "qp%d", qp_num);
                qp->debugfs_dir = debugfs_create_dir(debugfs_name,
-                                                    nt_debugfs_dir);
+                                                    nt->debugfs_node_dir);
 
                qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
                                                        qp->debugfs_dir, qp,
@@ -941,10 +974,10 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
        INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work);
        INIT_WORK(&qp->link_cleanup, ntb_qp_link_cleanup_work);
 
-       spin_lock_init(&qp->ntb_rx_pend_q_lock);
-       spin_lock_init(&qp->ntb_rx_free_q_lock);
+       spin_lock_init(&qp->ntb_rx_q_lock);
        spin_lock_init(&qp->ntb_tx_free_q_lock);
 
+       INIT_LIST_HEAD(&qp->rx_post_q);
        INIT_LIST_HEAD(&qp->rx_pend_q);
        INIT_LIST_HEAD(&qp->rx_free_q);
        INIT_LIST_HEAD(&qp->tx_free_q);
@@ -1031,6 +1064,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
                goto err2;
        }
 
+       if (nt_debugfs_dir) {
+               nt->debugfs_node_dir =
+                       debugfs_create_dir(pci_name(ndev->pdev),
+                                          nt_debugfs_dir);
+       }
+
        for (i = 0; i < qp_count; i++) {
                rc = ntb_transport_init_queue(nt, i);
                if (rc)
@@ -1107,22 +1146,47 @@ static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev)
        kfree(nt);
 }
 
-static void ntb_rx_copy_callback(void *data)
+static void ntb_complete_rxc(struct ntb_transport_qp *qp)
 {
-       struct ntb_queue_entry *entry = data;
-       struct ntb_transport_qp *qp = entry->qp;
-       void *cb_data = entry->cb_data;
-       unsigned int len = entry->len;
-       struct ntb_payload_header *hdr = entry->rx_hdr;
+       struct ntb_queue_entry *entry;
+       void *cb_data;
+       unsigned int len;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags);
+
+       while (!list_empty(&qp->rx_post_q)) {
+               entry = list_first_entry(&qp->rx_post_q,
+                                        struct ntb_queue_entry, entry);
+               if (!(entry->flags & DESC_DONE_FLAG))
+                       break;
+
+               entry->rx_hdr->flags = 0;
+               iowrite32(entry->index, &qp->rx_info->entry);
 
-       hdr->flags = 0;
+               cb_data = entry->cb_data;
+               len = entry->len;
 
-       iowrite32(entry->index, &qp->rx_info->entry);
+               list_move_tail(&entry->entry, &qp->rx_free_q);
 
-       ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+               spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
 
-       if (qp->rx_handler && qp->client_ready)
-               qp->rx_handler(qp, qp->cb_data, cb_data, len);
+               if (qp->rx_handler && qp->client_ready)
+                       qp->rx_handler(qp, qp->cb_data, cb_data, len);
+
+               spin_lock_irqsave(&qp->ntb_rx_q_lock, irqflags);
+       }
+
+       spin_unlock_irqrestore(&qp->ntb_rx_q_lock, irqflags);
+}
+
+static void ntb_rx_copy_callback(void *data)
+{
+       struct ntb_queue_entry *entry = data;
+
+       entry->flags |= DESC_DONE_FLAG;
+
+       ntb_complete_rxc(entry->qp);
 }
 
 static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
@@ -1138,19 +1202,18 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
        ntb_rx_copy_callback(entry);
 }
 
-static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset,
-                        size_t len)
+static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
 {
        struct dma_async_tx_descriptor *txd;
        struct ntb_transport_qp *qp = entry->qp;
        struct dma_chan *chan = qp->dma_chan;
        struct dma_device *device;
-       size_t pay_off, buff_off;
+       size_t pay_off, buff_off, len;
        struct dmaengine_unmap_data *unmap;
        dma_cookie_t cookie;
        void *buf = entry->buf;
 
-       entry->len = len;
+       len = entry->len;
 
        if (!chan)
                goto err;
@@ -1226,7 +1289,6 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
        struct ntb_payload_header *hdr;
        struct ntb_queue_entry *entry;
        void *offset;
-       int rc;
 
        offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index;
        hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header);
@@ -1255,65 +1317,43 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
                return -EIO;
        }
 
-       entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+       entry = ntb_list_mv(&qp->ntb_rx_q_lock, &qp->rx_pend_q, &qp->rx_post_q);
        if (!entry) {
                dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n");
                qp->rx_err_no_buf++;
-
-               rc = -ENOMEM;
-               goto err;
+               return -EAGAIN;
        }
 
+       entry->rx_hdr = hdr;
+       entry->index = qp->rx_index;
+
        if (hdr->len > entry->len) {
                dev_dbg(&qp->ndev->pdev->dev,
                        "receive buffer overflow! Wanted %d got %d\n",
                        hdr->len, entry->len);
                qp->rx_err_oflow++;
 
-               rc = -EIO;
-               goto err;
-       }
+               entry->len = -EIO;
+               entry->flags |= DESC_DONE_FLAG;
 
-       dev_dbg(&qp->ndev->pdev->dev,
-               "RX OK index %u ver %u size %d into buf size %d\n",
-               qp->rx_index, hdr->ver, hdr->len, entry->len);
+               ntb_complete_rxc(qp);
+       } else {
+               dev_dbg(&qp->ndev->pdev->dev,
+                       "RX OK index %u ver %u size %d into buf size %d\n",
+                       qp->rx_index, hdr->ver, hdr->len, entry->len);
 
-       qp->rx_bytes += hdr->len;
-       qp->rx_pkts++;
+               qp->rx_bytes += hdr->len;
+               qp->rx_pkts++;
 
-       entry->index = qp->rx_index;
-       entry->rx_hdr = hdr;
+               entry->len = hdr->len;
 
-       ntb_async_rx(entry, offset, hdr->len);
+               ntb_async_rx(entry, offset);
+       }
 
        qp->rx_index++;
        qp->rx_index %= qp->rx_max_entry;
 
        return 0;
-
-err:
-       /* FIXME: if this syncrhonous update of the rx_index gets ahead of
-        * asyncrhonous ntb_rx_copy_callback of previous entry, there are three
-        * scenarios:
-        *
-        * 1) The peer might miss this update, but observe the update
-        * from the memcpy completion callback.  In this case, the buffer will
-        * not be freed on the peer to be reused for a different packet.  The
-        * successful rx of a later packet would clear the condition, but the
-        * condition could persist if several rx fail in a row.
-        *
-        * 2) The peer may observe this update before the asyncrhonous copy of
-        * prior packets is completed.  The peer may overwrite the buffers of
-        * the prior packets before they are copied.
-        *
-        * 3) Both: the peer may observe the update, and then observe the index
-        * decrement by the asynchronous completion callback.  Who knows what
-        * badness that will cause.
-        */
-       hdr->flags = 0;
-       iowrite32(qp->rx_index, &qp->rx_info->entry);
-
-       return rc;
 }
 
 static void ntb_transport_rxc_db(unsigned long data)
@@ -1333,7 +1373,7 @@ static void ntb_transport_rxc_db(unsigned long data)
                        break;
        }
 
-       if (qp->dma_chan)
+       if (i && qp->dma_chan)
                dma_async_issue_pending(qp->dma_chan);
 
        if (i == qp->rx_max_entry) {
@@ -1609,7 +1649,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
                        goto err1;
 
                entry->qp = qp;
-               ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry,
+               ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry,
                             &qp->rx_free_q);
        }
 
@@ -1634,7 +1674,7 @@ err2:
        while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
                kfree(entry);
 err1:
-       while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
                kfree(entry);
        if (qp->dma_chan)
                dma_release_channel(qp->dma_chan);
@@ -1652,7 +1692,6 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue);
  */
 void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 {
-       struct ntb_transport_ctx *nt = qp->transport;
        struct pci_dev *pdev;
        struct ntb_queue_entry *entry;
        u64 qp_bit;
@@ -1689,18 +1728,23 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
        qp->tx_handler = NULL;
        qp->event_handler = NULL;
 
-       while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
                kfree(entry);
 
-       while ((entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q))) {
-               dev_warn(&pdev->dev, "Freeing item from a non-empty queue\n");
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q))) {
+               dev_warn(&pdev->dev, "Freeing item from non-empty rx_pend_q\n");
+               kfree(entry);
+       }
+
+       while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_post_q))) {
+               dev_warn(&pdev->dev, "Freeing item from non-empty rx_post_q\n");
                kfree(entry);
        }
 
        while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
                kfree(entry);
 
-       nt->qp_bitmap_free |= qp_bit;
+       qp->transport->qp_bitmap_free |= qp_bit;
 
        dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num);
 }
@@ -1724,14 +1768,14 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len)
        if (!qp || qp->client_ready)
                return NULL;
 
-       entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q);
+       entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q);
        if (!entry)
                return NULL;
 
        buf = entry->cb_data;
        *len = entry->len;
 
-       ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
+       ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_free_q);
 
        return buf;
 }
@@ -1757,15 +1801,18 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
        if (!qp)
                return -EINVAL;
 
-       entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q);
+       entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q);
        if (!entry)
                return -ENOMEM;
 
        entry->cb_data = cb;
        entry->buf = data;
        entry->len = len;
+       entry->flags = 0;
+
+       ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q);
 
-       ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q);
+       tasklet_schedule(&qp->rxc_db_work);
 
        return 0;
 }
index 8eb22c0ca7ce40ea030bd7be11bf8f0f0c10c10a..7e2c43f701bc451463c5273ed3a5a1e49f6be15f 100644 (file)
@@ -535,8 +535,6 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
                                        __func__, dimm_name, cmd_name, i);
                        return -ENXIO;
                }
-               if (!access_ok(VERIFY_READ, p + in_len, in_size))
-                       return -EFAULT;
                if (in_len < sizeof(in_env))
                        copy = min_t(u32, sizeof(in_env) - in_len, in_size);
                else
@@ -557,8 +555,6 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
                                        __func__, dimm_name, cmd_name, i);
                        return -EFAULT;
                }
-               if (!access_ok(VERIFY_WRITE, p + in_len + out_len, out_size))
-                       return -EFAULT;
                if (out_len < sizeof(out_env))
                        copy = min_t(u32, sizeof(out_env) - out_len, out_size);
                else
@@ -570,9 +566,6 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
        }
 
        buf_len = out_len + in_len;
-       if (!access_ok(VERIFY_WRITE, p, sizeof(buf_len)))
-               return -EFAULT;
-
        if (buf_len > ND_IOCTL_MAX_BUFLEN) {
                dev_dbg(dev, "%s:%s cmd: %s buf_len: %zu > %d\n", __func__,
                                dimm_name, cmd_name, buf_len,
@@ -706,8 +699,10 @@ int __init nvdimm_bus_init(void)
        nvdimm_major = rc;
 
        nd_class = class_create(THIS_MODULE, "nd");
-       if (IS_ERR(nd_class))
+       if (IS_ERR(nd_class)) {
+               rc = PTR_ERR(nd_class);
                goto err_class;
+       }
 
        return 0;
 
index a5233422f9dc5f770b98d0555560fb87a5f83ff0..7384455792bfb629ed6a2b9a5dbe40d1f58f2627 100644 (file)
@@ -458,10 +458,15 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
                nvdimm_bus_unlock(dev);
        }
        if (is_nd_btt(dev) && probe) {
+               struct nd_btt *nd_btt = to_nd_btt(dev);
+
                nd_region = to_nd_region(dev->parent);
                nvdimm_bus_lock(dev);
                if (nd_region->btt_seed == dev)
                        nd_region_create_btt_seed(nd_region);
+               if (nd_region->ns_seed == &nd_btt->ndns->dev &&
+                               is_nd_blk(dev->parent))
+                       nd_region_create_blk_seed(nd_region);
                nvdimm_bus_unlock(dev);
        }
 }
index 8df1b1777745e8e0dfb46611197a8238c929af4e..59bb8556e43ac8f975485465ca8d1b0fdfeba3c5 100644 (file)
@@ -47,7 +47,7 @@ config OF_DYNAMIC
 
 config OF_ADDRESS
        def_bool y
-       depends on !SPARC
+       depends on !SPARC && HAS_IOMEM
        select OF_ADDRESS_PCI if PCI
 
 config OF_ADDRESS_PCI
index 18016341d5a91656b29220b414faddae48188648..9f71770b6226f9ed3d4ceab7bb95ea3f4ba55b6c 100644 (file)
@@ -979,7 +979,6 @@ static struct platform_driver unittest_driver = {
        .remove                 = unittest_remove,
        .driver = {
                .name           = "unittest",
-               .owner          = THIS_MODULE,
                .of_match_table = of_match_ptr(unittest_match),
        },
 };
@@ -1666,7 +1665,6 @@ static const struct i2c_device_id unittest_i2c_dev_id[] = {
 static struct i2c_driver unittest_i2c_dev_driver = {
        .driver = {
                .name = "unittest-i2c-dev",
-               .owner = THIS_MODULE,
        },
        .probe = unittest_i2c_dev_probe,
        .remove = unittest_i2c_dev_remove,
@@ -1761,7 +1759,6 @@ static const struct i2c_device_id unittest_i2c_mux_id[] = {
 static struct i2c_driver unittest_i2c_mux_driver = {
        .driver = {
                .name = "unittest-i2c-mux",
-               .owner = THIS_MODULE,
        },
        .probe = unittest_i2c_mux_probe,
        .remove = unittest_i2c_mux_remove,
index 8067f54ce050a6c8cf3a4c18d9b4ea560f017d94..5ce5ef211bdbdf575752e150edc6e26cc683e82d 100644 (file)
@@ -891,8 +891,10 @@ parport_register_dev_model(struct parport *port, const char *name,
        par_dev->dev.release = free_pardevice;
        par_dev->devmodel = true;
        ret = device_register(&par_dev->dev);
-       if (ret)
-               goto err_put_dev;
+       if (ret) {
+               put_device(&par_dev->dev);
+               goto err_put_port;
+       }
 
        /* Chain this onto the list */
        par_dev->prev = NULL;
@@ -907,7 +909,8 @@ parport_register_dev_model(struct parport *port, const char *name,
                        spin_unlock(&port->physport->pardevice_lock);
                        pr_debug("%s: cannot grant exclusive access for device %s\n",
                                 port->name, name);
-                       goto err_put_dev;
+                       device_unregister(&par_dev->dev);
+                       goto err_put_port;
                }
                port->flags |= PARPORT_FLAG_EXCL;
        }
@@ -938,8 +941,6 @@ parport_register_dev_model(struct parport *port, const char *name,
 
        return par_dev;
 
-err_put_dev:
-       put_device(&par_dev->dev);
 err_free_devname:
        kfree(devname);
 err_free_par_dev:
index 73de4efcbe6edc85c8f3fb54e0c925a7ab30492b..944f50015ed07b41b2de0da464812910c411cc1a 100644 (file)
@@ -2,7 +2,7 @@
 # PCI configuration
 #
 config PCI_BUS_ADDR_T_64BIT
-       def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT)
+       def_bool y if (ARCH_DMA_ADDR_T_64BIT || (64BIT && !PARISC))
        depends on PCI
 
 config PCI_MSI
index cefd636681b6418ce75376879dc26fe3891bc47d..b978bbfe044c163be9cf1a0a4f35bb1edbbab783 100644 (file)
@@ -997,7 +997,12 @@ void set_pcie_port_type(struct pci_dev *pdev)
        else if (type == PCI_EXP_TYPE_UPSTREAM ||
                 type == PCI_EXP_TYPE_DOWNSTREAM) {
                parent = pci_upstream_bridge(pdev);
-               if (!parent->has_secondary_link)
+
+               /*
+                * Usually there's an upstream device (Root Port or Switch
+                * Downstream Port), but we can't assume one exists.
+                */
+               if (parent && !parent->has_secondary_link)
                        pdev->has_secondary_link = 1;
        }
 }
index c0e6ede3e27d7cd07d92c247af58367e1b6d85a1..6b8dd162f644214ba24fd666b5aa6c94467d964d 100644 (file)
@@ -56,6 +56,7 @@ config PHY_EXYNOS_MIPI_VIDEO
 
 config PHY_PXA_28NM_HSIC
        tristate "Marvell USB HSIC 28nm PHY Driver"
+       depends on HAS_IOMEM
        select GENERIC_PHY
        help
          Enable this to support Marvell USB HSIC PHY driver for Marvell
@@ -66,6 +67,7 @@ config PHY_PXA_28NM_HSIC
 
 config PHY_PXA_28NM_USB2
        tristate "Marvell USB 2.0 28nm PHY Driver"
+       depends on HAS_IOMEM
        select GENERIC_PHY
        help
          Enable this to support Marvell USB 2.0 PHY driver for Marvell
index c6fc95b530835569b040f193f6cf051f7198f7b9..335e06d66ed9a5100cbdda511e6c206238651814 100644 (file)
 
 static const u32 phy_berlin_pll_dividers[] = {
        /* Berlin 2 */
-       CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
-       /* Berlin 2CD */
        CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
+       /* Berlin 2CD/Q */
+       CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
 };
 
 struct phy_berlin_usb_priv {
index e17c539e4f6fbb138c04957532f3a329a8556b4a..2dad7e820ff0b16b7447b708f0c147b2e0289f02 100644 (file)
@@ -212,6 +212,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
 
        sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
 }
+EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
 
 static struct phy_ops sun4i_usb_phy_ops = {
        .init           = sun4i_usb_phy_init,
index 53f295c1bab1a72108d84b955714b8aef4d7e951..08020dc2c7c8c3496987589841fc0ddb0b1c9ff7 100644 (file)
@@ -28,7 +28,8 @@
 #include <linux/delay.h>
 #include <linux/phy/omap_control_phy.h>
 #include <linux/of_platform.h>
-#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #define        PLL_STATUS              0x00000004
 #define        PLL_GO                  0x00000008
@@ -53,6 +54,8 @@
 #define        PLL_LOCK                0x2
 #define        PLL_IDLE                0x1
 
+#define SATA_PLL_SOFT_RESET    BIT(18)
+
 /*
  * This is an Empirical value that works, need to confirm the actual
  * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
@@ -83,10 +86,9 @@ struct ti_pipe3 {
        struct clk              *refclk;
        struct clk              *div_clk;
        struct pipe3_dpll_map   *dpll_map;
-       bool                    enabled;
-       spinlock_t              lock;   /* serialize clock enable/disable */
-       /* the below flag is needed specifically for SATA */
-       bool                    refclk_enabled;
+       struct regmap           *dpll_reset_syscon; /* ctrl. reg. acces */
+       unsigned int            dpll_reset_reg; /* reg. index within syscon */
+       bool                    sata_refclk_enabled;
 };
 
 static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -137,6 +139,9 @@ static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
        return NULL;
 }
 
+static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy);
+static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy);
+
 static int ti_pipe3_power_off(struct phy *x)
 {
        struct ti_pipe3 *phy = phy_get_drvdata(x);
@@ -217,6 +222,7 @@ static int ti_pipe3_init(struct phy *x)
        u32 val;
        int ret = 0;
 
+       ti_pipe3_enable_clocks(phy);
        /*
         * Set pcie_pcs register to 0x96 for proper functioning of phy
         * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table
@@ -250,33 +256,46 @@ static int ti_pipe3_exit(struct phy *x)
        u32 val;
        unsigned long timeout;
 
-       /* SATA DPLL can't be powered down due to Errata i783 and PCIe
-        * does not have internal DPLL
+       /* If dpll_reset_syscon is not present we wont power down SATA DPLL
+        * due to Errata i783
         */
-       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") ||
-           of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie"))
+       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") &&
+           !phy->dpll_reset_syscon)
                return 0;
 
-       /* Put DPLL in IDLE mode */
-       val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
-       val |= PLL_IDLE;
-       ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+       /* PCIe doesn't have internal DPLL */
+       if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) {
+               /* Put DPLL in IDLE mode */
+               val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+               val |= PLL_IDLE;
+               ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 
-       /* wait for LDO and Oscillator to power down */
-       timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
-       do {
-               cpu_relax();
-               val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
-               if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
-                       break;
-       } while (!time_after(jiffies, timeout));
+               /* wait for LDO and Oscillator to power down */
+               timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
+               do {
+                       cpu_relax();
+                       val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+                       if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+                               break;
+               } while (!time_after(jiffies, timeout));
+
+               if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+                       dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
+                               val);
+                       return -EBUSY;
+               }
+       }
 
-       if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
-               dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
-                       val);
-               return -EBUSY;
+       /* i783: SATA needs control bit toggle after PLL unlock */
+       if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) {
+               regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+                                  SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET);
+               regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg,
+                                  SATA_PLL_SOFT_RESET, 0);
        }
 
+       ti_pipe3_disable_clocks(phy);
+
        return 0;
 }
 static struct phy_ops ops = {
@@ -306,7 +325,6 @@ static int ti_pipe3_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        phy->dev                = &pdev->dev;
-       spin_lock_init(&phy->lock);
 
        if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
                match = of_match_device(ti_pipe3_id_table, &pdev->dev);
@@ -350,6 +368,21 @@ static int ti_pipe3_probe(struct platform_device *pdev)
                }
        } else {
                phy->wkupclk = ERR_PTR(-ENODEV);
+               phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node,
+                                                       "syscon-pllreset");
+               if (IS_ERR(phy->dpll_reset_syscon)) {
+                       dev_info(&pdev->dev,
+                                "can't get syscon-pllreset, sata dpll won't idle\n");
+                       phy->dpll_reset_syscon = NULL;
+               } else {
+                       if (of_property_read_u32_index(node,
+                                                      "syscon-pllreset", 1,
+                                                      &phy->dpll_reset_reg)) {
+                               dev_err(&pdev->dev,
+                                       "couldn't get pllreset reg. offset\n");
+                               return -EINVAL;
+                       }
+               }
        }
 
        if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
@@ -403,6 +436,16 @@ static int ti_pipe3_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, phy);
        pm_runtime_enable(phy->dev);
 
+       /*
+        * Prevent auto-disable of refclk for SATA PHY due to Errata i783
+        */
+       if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+               if (!IS_ERR(phy->refclk)) {
+                       clk_prepare_enable(phy->refclk);
+                       phy->sata_refclk_enabled = true;
+               }
+       }
+
        generic_phy = devm_phy_create(phy->dev, NULL, &ops);
        if (IS_ERR(generic_phy))
                return PTR_ERR(generic_phy);
@@ -413,63 +456,33 @@ static int ti_pipe3_probe(struct platform_device *pdev)
        if (IS_ERR(phy_provider))
                return PTR_ERR(phy_provider);
 
-       pm_runtime_get(&pdev->dev);
-
        return 0;
 }
 
 static int ti_pipe3_remove(struct platform_device *pdev)
 {
-       if (!pm_runtime_suspended(&pdev->dev))
-               pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
+static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
 {
-       if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
-               int ret;
+       int ret = 0;
 
+       if (!IS_ERR(phy->refclk)) {
                ret = clk_prepare_enable(phy->refclk);
                if (ret) {
                        dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
                        return ret;
                }
-               phy->refclk_enabled = true;
        }
 
-       return 0;
-}
-
-static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
-{
-       if (!IS_ERR(phy->refclk))
-               clk_disable_unprepare(phy->refclk);
-
-       phy->refclk_enabled = false;
-}
-
-static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&phy->lock, flags);
-       if (phy->enabled)
-               goto err1;
-
-       ret = ti_pipe3_enable_refclk(phy);
-       if (ret)
-               goto err1;
-
        if (!IS_ERR(phy->wkupclk)) {
                ret = clk_prepare_enable(phy->wkupclk);
                if (ret) {
                        dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
-                       goto err2;
+                       goto disable_refclk;
                }
        }
 
@@ -477,96 +490,43 @@ static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
                ret = clk_prepare_enable(phy->div_clk);
                if (ret) {
                        dev_err(phy->dev, "Failed to enable div_clk %d\n", ret);
-                       goto err3;
+                       goto disable_wkupclk;
                }
        }
 
-       phy->enabled = true;
-       spin_unlock_irqrestore(&phy->lock, flags);
        return 0;
 
-err3:
+disable_wkupclk:
        if (!IS_ERR(phy->wkupclk))
                clk_disable_unprepare(phy->wkupclk);
 
-err2:
+disable_refclk:
        if (!IS_ERR(phy->refclk))
                clk_disable_unprepare(phy->refclk);
 
-       ti_pipe3_disable_refclk(phy);
-err1:
-       spin_unlock_irqrestore(&phy->lock, flags);
        return ret;
 }
 
 static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&phy->lock, flags);
-       if (!phy->enabled) {
-               spin_unlock_irqrestore(&phy->lock, flags);
-               return;
-       }
-
        if (!IS_ERR(phy->wkupclk))
                clk_disable_unprepare(phy->wkupclk);
-       /* Don't disable refclk for SATA PHY due to Errata i783 */
-       if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
-               ti_pipe3_disable_refclk(phy);
+       if (!IS_ERR(phy->refclk)) {
+               clk_disable_unprepare(phy->refclk);
+               /*
+                * SATA refclk needs an additional disable as we left it
+                * on in probe to avoid Errata i783
+                */
+               if (phy->sata_refclk_enabled) {
+                       clk_disable_unprepare(phy->refclk);
+                       phy->sata_refclk_enabled = false;
+               }
+       }
+
        if (!IS_ERR(phy->div_clk))
                clk_disable_unprepare(phy->div_clk);
-       phy->enabled = false;
-       spin_unlock_irqrestore(&phy->lock, flags);
 }
 
-static int ti_pipe3_runtime_suspend(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-
-       ti_pipe3_disable_clocks(phy);
-       return 0;
-}
-
-static int ti_pipe3_runtime_resume(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-       int ret = 0;
-
-       ret = ti_pipe3_enable_clocks(phy);
-       return ret;
-}
-
-static int ti_pipe3_suspend(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-
-       ti_pipe3_disable_clocks(phy);
-       return 0;
-}
-
-static int ti_pipe3_resume(struct device *dev)
-{
-       struct ti_pipe3 *phy = dev_get_drvdata(dev);
-       int ret;
-
-       ret = ti_pipe3_enable_clocks(phy);
-       if (ret)
-               return ret;
-
-       pm_runtime_disable(dev);
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops ti_pipe3_pm_ops = {
-       SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
-                          ti_pipe3_runtime_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
-};
-
 static const struct of_device_id ti_pipe3_id_table[] = {
        {
                .compatible = "ti,phy-usb3",
@@ -592,7 +552,6 @@ static struct platform_driver ti_pipe3_driver = {
        .remove         = ti_pipe3_remove,
        .driver         = {
                .name   = "ti-pipe3",
-               .pm     = &ti_pipe3_pm_ops,
                .of_match_table = ti_pipe3_id_table,
        },
 };
index efcf2a2b3975c2cc35fda3806223f0578900d4c2..6177315ab74e5eb43cc92fa9d57c892fadce4b40 100644 (file)
@@ -473,6 +473,8 @@ static void bcm2835_gpio_irq_disable(struct irq_data *data)
 
        spin_lock_irqsave(&pc->irq_lock[bank], flags);
        bcm2835_gpio_irq_config(pc, gpio, false);
+       /* Clear events that were latched prior to clearing event sources */
+       bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
        clear_bit(offset, &pc->enabled_irq_map[bank]);
        spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
 }
index 5fd4437cee1584a6cc7a5251269d1078a0b62ddf..88a7fac11bd499f72c831b91f0f6c05bd29b19f7 100644 (file)
@@ -403,14 +403,13 @@ static int imx1_pinconf_set(struct pinctrl_dev *pctldev,
                             unsigned num_configs)
 {
        struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx1_pinctrl_soc_info *info = ipctl->info;
        int i;
 
        for (i = 0; i != num_configs; ++i) {
                imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN);
 
                dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n",
-                       info->pins[pin_id].name);
+                       pin_desc_get(pctldev, pin_id)->name);
        }
 
        return 0;
index 557d0f2a3031b1a0295fe60796ec17ea7817fc52..97681fac082e71f449874a4a5a21a68b07e27fc2 100644 (file)
@@ -787,7 +787,6 @@ static const struct pinmux_ops abx500_pinmux_ops = {
        .set_mux = abx500_pmx_set,
        .gpio_request_enable = abx500_gpio_request_enable,
        .gpio_disable_free = abx500_gpio_disable_free,
-       .strict = true,
 };
 
 static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
index ef0b697639a71e397ec545d17f6fe9ae9cec445d..347c763a6a78762302c89559a5ff92b64ec55872 100644 (file)
@@ -823,7 +823,7 @@ static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
                break;
 
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-               if (param)
+               if (param_val)
                        *reg &= ~(LPC18XX_SCU_I2C0_ZIF << shift);
                else
                        *reg |= (LPC18XX_SCU_I2C0_ZIF << shift);
@@ -876,7 +876,7 @@ static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev,
                break;
 
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-               if (param)
+               if (param_val)
                        *reg &= ~LPC18XX_SCU_PIN_ZIF;
                else
                        *reg |= LPC18XX_SCU_PIN_ZIF;
index b2de09d3b1a0c8e14b03e23fcb0131e6f41022ee..0b8d480171a3dfea7af0aa8b03e346d56b80f6bb 100644 (file)
@@ -1760,7 +1760,8 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs,
                int res;
 
                res = request_irq(pcs_soc->irq, pcs_irq_handler,
-                                 IRQF_SHARED | IRQF_NO_SUSPEND,
+                                 IRQF_SHARED | IRQF_NO_SUSPEND |
+                                 IRQF_NO_THREAD,
                                  name, pcs_soc);
                if (res) {
                        pcs_soc->irq = -1;
index 3dd5a3b2ac62344a19713e92d9e7ad8fa5cf2461..c760bf43d116cfaa83370d640deefd38abb9f407 100644 (file)
 #include "../core.h"
 #include "pinctrl-samsung.h"
 
-#define GROUP_SUFFIX           "-grp"
-#define GSUFFIX_LEN            sizeof(GROUP_SUFFIX)
-#define FUNCTION_SUFFIX                "-mux"
-#define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
-
 /* list of all possible config options supported */
 static struct pin_config {
        const char *property;
index c7508d5f688613b26e6eb226628f61ba9cd38f66..0874cfee6889afa149fc18895de55c12ac2e5ff0 100644 (file)
@@ -224,7 +224,7 @@ struct sh_pfc_soc_info {
 
 /* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */
 #define _GP_GPIO(bank, _pin, _name, sfx)                               \
-       [(bank * 32) + _pin] = {                                        \
+       {                                                               \
                .pin = (bank * 32) + _pin,                              \
                .name = __stringify(_name),                             \
                .enum_id = _name##_DATA,                                \
index f87a5eaf75dab42129491a07e1ba148baec0ef82..0afaf79a4e5175f99233726d07ea086758e72623 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * Inspired from:
  * - U300 Pinctl drivers
index dc8bf85ecb2aa5ae33f8de6dc6057dfd526fcbbd..27c2cc8d83adcf8d9e60a91460c20b7cfc2e2dcf 100644 (file)
@@ -2,7 +2,7 @@
  * Driver header file for the ST Microelectronics SPEAr pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index a7bdc537efa79d1c744e88f6e44353a0b2f92c43..92611bb757acc2f4bbd75efdd575b6b3eb839e0b 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr1310 pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -2730,7 +2730,7 @@ static void __exit spear1310_pinctrl_exit(void)
 }
 module_exit(spear1310_pinctrl_exit);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("ST Microelectronics SPEAr1310 pinctrl driver");
 MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(of, spear1310_pinctrl_of_match);
index f43ec85a03285db1ee473ae7d5140e0d87811642..f842e9dc40d0a85c5c056524edfb3752fe519597 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr1340 pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -2046,7 +2046,7 @@ static void __exit spear1340_pinctrl_exit(void)
 }
 module_exit(spear1340_pinctrl_exit);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("ST Microelectronics SPEAr1340 pinctrl driver");
 MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(of, spear1340_pinctrl_of_match);
index da8990a8eeefcb6b0f4666bd60efdb7de3e9f384..d998a2ccff48ebd00b2a63ed938032ecc2b58a5c 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr300 pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -703,7 +703,7 @@ static void __exit spear300_pinctrl_exit(void)
 }
 module_exit(spear300_pinctrl_exit);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver");
 MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match);
index 31ede51e819bf0e41d1c4a8ba9946b6f395c7421..609b18aceb161269bf41e925930d096ceaae8afb 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr310 pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -426,7 +426,7 @@ static void __exit spear310_pinctrl_exit(void)
 }
 module_exit(spear310_pinctrl_exit);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
 MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(of, spear310_pinctrl_of_match);
index 506e40b641e048950d0f133dcdc5639112f7b4f2..c07114431bd46c6541409e67c920ff6825a94a07 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr320 pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -3467,7 +3467,7 @@ static void __exit spear320_pinctrl_exit(void)
 }
 module_exit(spear320_pinctrl_exit);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver");
 MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match);
index 12ee21af766b1ffafedc935e4bebbdb00065baf6..d3119aafe7090c66798c458534774509e5c4120e 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for the ST Microelectronics SPEAr3xx pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 7860b36053c4523f69a5861f9fd832afae0983e8..ce19dcf8f08b256a70e017afa7871ecac9c20569 100644 (file)
@@ -2,7 +2,7 @@
  * Header file for the ST Microelectronics SPEAr3xx pinmux
  *
  * Copyright (C) 2012 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index cb13299195271ffed4854ed6b0b593c5e8487019..3271cd1abe7c0e6c5d2e813171aa5df494f9d977 100644 (file)
@@ -4,7 +4,6 @@
 
 menuconfig CHROME_PLATFORMS
        bool "Platform support for Chrome hardware"
-       depends on X86 || ARM
        ---help---
          Say Y here to get to see options for platform support for
          various Chromebooks and Chromeboxes. This option alone does
index ed317ccac4a2dc8c490291cb561bb986203dcef2..aaeeae81e3a9798de43aaa80fb4aba2f247ad3ab 100644 (file)
@@ -309,12 +309,15 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
 static struct calling_interface_buffer *buffer;
 static DEFINE_MUTEX(buffer_mutex);
 
-static int hwswitch_state;
+static void clear_buffer(void)
+{
+       memset(buffer, 0, sizeof(struct calling_interface_buffer));
+}
 
 static void get_buffer(void)
 {
        mutex_lock(&buffer_mutex);
-       memset(buffer, 0, sizeof(struct calling_interface_buffer));
+       clear_buffer();
 }
 
 static void release_buffer(void)
@@ -548,21 +551,41 @@ static int dell_rfkill_set(void *data, bool blocked)
        int disable = blocked ? 1 : 0;
        unsigned long radio = (unsigned long)data;
        int hwswitch_bit = (unsigned long)data - 1;
+       int hwswitch;
+       int status;
+       int ret;
 
        get_buffer();
+
+       dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
+       status = buffer->output[1];
+
+       if (ret != 0)
+               goto out;
+
+       clear_buffer();
+
+       buffer->input[0] = 0x2;
        dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
+       hwswitch = buffer->output[1];
 
        /* If the hardware switch controls this radio, and the hardware
           switch is disabled, always disable the radio */
-       if ((hwswitch_state & BIT(hwswitch_bit)) &&
-           !(buffer->output[1] & BIT(16)))
+       if (ret == 0 && (hwswitch & BIT(hwswitch_bit)) &&
+           (status & BIT(0)) && !(status & BIT(16)))
                disable = 1;
 
+       clear_buffer();
+
        buffer->input[0] = (1 | (radio<<8) | (disable << 16));
        dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
 
+ out:
        release_buffer();
-       return 0;
+       return dell_smi_error(ret);
 }
 
 /* Must be called with the buffer held */
@@ -572,6 +595,7 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
        if (status & BIT(0)) {
                /* Has hw-switch, sync sw_state to BIOS */
                int block = rfkill_blocked(rfkill);
+               clear_buffer();
                buffer->input[0] = (1 | (radio << 8) | (block << 16));
                dell_send_request(buffer, 17, 11);
        } else {
@@ -581,23 +605,43 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio,
 }
 
 static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio,
-                                       int status)
+                                       int status, int hwswitch)
 {
-       if (hwswitch_state & (BIT(radio - 1)))
+       if (hwswitch & (BIT(radio - 1)))
                rfkill_set_hw_state(rfkill, !(status & BIT(16)));
 }
 
 static void dell_rfkill_query(struct rfkill *rfkill, void *data)
 {
+       int radio = ((unsigned long)data & 0xF);
+       int hwswitch;
        int status;
+       int ret;
 
        get_buffer();
+
        dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
        status = buffer->output[1];
 
-       dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status);
+       if (ret != 0 || !(status & BIT(0))) {
+               release_buffer();
+               return;
+       }
+
+       clear_buffer();
+
+       buffer->input[0] = 0x2;
+       dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
+       hwswitch = buffer->output[1];
 
        release_buffer();
+
+       if (ret != 0)
+               return;
+
+       dell_rfkill_update_hw_state(rfkill, radio, status, hwswitch);
 }
 
 static const struct rfkill_ops dell_rfkill_ops = {
@@ -609,13 +653,27 @@ static struct dentry *dell_laptop_dir;
 
 static int dell_debugfs_show(struct seq_file *s, void *data)
 {
+       int hwswitch_state;
+       int hwswitch_ret;
        int status;
+       int ret;
 
        get_buffer();
+
        dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
        status = buffer->output[1];
+
+       clear_buffer();
+
+       buffer->input[0] = 0x2;
+       dell_send_request(buffer, 17, 11);
+       hwswitch_ret = buffer->output[0];
+       hwswitch_state = buffer->output[1];
+
        release_buffer();
 
+       seq_printf(s, "return:\t%d\n", ret);
        seq_printf(s, "status:\t0x%X\n", status);
        seq_printf(s, "Bit 0 : Hardware switch supported:   %lu\n",
                   status & BIT(0));
@@ -657,7 +715,8 @@ static int dell_debugfs_show(struct seq_file *s, void *data)
        seq_printf(s, "Bit 21: WiGig is blocked:            %lu\n",
                  (status & BIT(21)) >> 21);
 
-       seq_printf(s, "\nhwswitch_state:\t0x%X\n", hwswitch_state);
+       seq_printf(s, "\nhwswitch_return:\t%d\n", hwswitch_ret);
+       seq_printf(s, "hwswitch_state:\t0x%X\n", hwswitch_state);
        seq_printf(s, "Bit 0 : Wifi controlled by switch:      %lu\n",
                   hwswitch_state & BIT(0));
        seq_printf(s, "Bit 1 : Bluetooth controlled by switch: %lu\n",
@@ -693,25 +752,43 @@ static const struct file_operations dell_debugfs_fops = {
 
 static void dell_update_rfkill(struct work_struct *ignored)
 {
+       int hwswitch = 0;
        int status;
+       int ret;
 
        get_buffer();
+
        dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
        status = buffer->output[1];
 
+       if (ret != 0)
+               goto out;
+
+       clear_buffer();
+
+       buffer->input[0] = 0x2;
+       dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
+
+       if (ret == 0 && (status & BIT(0)))
+               hwswitch = buffer->output[1];
+
        if (wifi_rfkill) {
-               dell_rfkill_update_hw_state(wifi_rfkill, 1, status);
+               dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch);
                dell_rfkill_update_sw_state(wifi_rfkill, 1, status);
        }
        if (bluetooth_rfkill) {
-               dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status);
+               dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status,
+                                           hwswitch);
                dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status);
        }
        if (wwan_rfkill) {
-               dell_rfkill_update_hw_state(wwan_rfkill, 3, status);
+               dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch);
                dell_rfkill_update_sw_state(wwan_rfkill, 3, status);
        }
 
+ out:
        release_buffer();
 }
 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
@@ -773,21 +850,17 @@ static int __init dell_setup_rfkill(void)
 
        get_buffer();
        dell_send_request(buffer, 17, 11);
+       ret = buffer->output[0];
        status = buffer->output[1];
-       buffer->input[0] = 0x2;
-       dell_send_request(buffer, 17, 11);
-       hwswitch_state = buffer->output[1];
        release_buffer();
 
-       if (!(status & BIT(0))) {
-               if (force_rfkill) {
-                       /* No hwsitch, clear all hw-controlled bits */
-                       hwswitch_state &= ~7;
-               } else {
-                       /* rfkill is only tested on laptops with a hwswitch */
-                       return 0;
-               }
-       }
+       /* dell wireless info smbios call is not supported */
+       if (ret != 0)
+               return 0;
+
+       /* rfkill is only tested on laptops with a hwswitch */
+       if (!(status & BIT(0)) && !force_rfkill)
+               return 0;
 
        if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
                wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
@@ -932,47 +1005,50 @@ static void dell_cleanup_rfkill(void)
 
 static int dell_send_intensity(struct backlight_device *bd)
 {
-       int ret = 0;
+       int token;
+       int ret;
+
+       token = find_token_location(BRIGHTNESS_TOKEN);
+       if (token == -1)
+               return -ENODEV;
 
        get_buffer();
-       buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
+       buffer->input[0] = token;
        buffer->input[1] = bd->props.brightness;
 
-       if (buffer->input[0] == -1) {
-               ret = -ENODEV;
-               goto out;
-       }
-
        if (power_supply_is_system_supplied() > 0)
                dell_send_request(buffer, 1, 2);
        else
                dell_send_request(buffer, 1, 1);
 
- out:
+       ret = dell_smi_error(buffer->output[0]);
+
        release_buffer();
        return ret;
 }
 
 static int dell_get_intensity(struct backlight_device *bd)
 {
-       int ret = 0;
+       int token;
+       int ret;
 
-       get_buffer();
-       buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
+       token = find_token_location(BRIGHTNESS_TOKEN);
+       if (token == -1)
+               return -ENODEV;
 
-       if (buffer->input[0] == -1) {
-               ret = -ENODEV;
-               goto out;
-       }
+       get_buffer();
+       buffer->input[0] = token;
 
        if (power_supply_is_system_supplied() > 0)
                dell_send_request(buffer, 0, 2);
        else
                dell_send_request(buffer, 0, 1);
 
-       ret = buffer->output[1];
+       if (buffer->output[0])
+               ret = dell_smi_error(buffer->output[0]);
+       else
+               ret = buffer->output[1];
 
- out:
        release_buffer();
        return ret;
 }
@@ -2036,6 +2112,7 @@ static void kbd_led_exit(void)
 static int __init dell_init(void)
 {
        int max_intensity = 0;
+       int token;
        int ret;
 
        if (!dmi_check_system(dell_device_table))
@@ -2094,13 +2171,15 @@ static int __init dell_init(void)
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                return 0;
 
-       get_buffer();
-       buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
-       if (buffer->input[0] != -1) {
+       token = find_token_location(BRIGHTNESS_TOKEN);
+       if (token != -1) {
+               get_buffer();
+               buffer->input[0] = token;
                dell_send_request(buffer, 0, 2);
-               max_intensity = buffer->output[3];
+               if (buffer->output[0] == 0)
+                       max_intensity = buffer->output[3];
+               release_buffer();
        }
-       release_buffer();
 
        if (max_intensity) {
                struct backlight_properties props;
index d734763dab6970fac3b9916a4596b1fe2d0fcd58..105cfffe82c617297d0bf348c1c5ae669060b4d2 100644 (file)
@@ -96,18 +96,18 @@ static struct intel_pmc_ipc_dev {
        struct completion cmd_complete;
 
        /* The following PMC BARs share the same ACPI device with the IPC */
-       void *acpi_io_base;
+       resource_size_t acpi_io_base;
        int acpi_io_size;
        struct platform_device *tco_dev;
 
        /* gcr */
-       void *gcr_base;
+       resource_size_t gcr_base;
        int gcr_size;
 
        /* punit */
-       void *punit_base;
+       resource_size_t punit_base;
        int punit_size;
-       void *punit_base2;
+       resource_size_t punit_base2;
        int punit_size2;
        struct platform_device *punit_dev;
 } ipcdev;
@@ -210,10 +210,15 @@ static int intel_pmc_ipc_check_status(void)
        return ret;
 }
 
-/*
- * intel_pmc_ipc_simple_command
- * @cmd: command
- * @sub: sub type
+/**
+ * intel_pmc_ipc_simple_command() - Simple IPC command
+ * @cmd:       IPC command code.
+ * @sub:       IPC command sub type.
+ *
+ * Send a simple IPC command to PMC when don't need to specify
+ * input/output data and source/dest pointers.
+ *
+ * Return:     an IPC error code or 0 on success.
  */
 int intel_pmc_ipc_simple_command(int cmd, int sub)
 {
@@ -232,16 +237,20 @@ int intel_pmc_ipc_simple_command(int cmd, int sub)
 }
 EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command);
 
-/*
- * intel_pmc_ipc_raw_cmd
- * @cmd: command
- * @sub: sub type
- * @in: input data
- * @inlen: input length in bytes
- * @out: output data
- * @outlen: output length in dwords
- * @sptr: data writing to SPTR register
- * @dptr: data writing to DPTR register
+/**
+ * intel_pmc_ipc_raw_cmd() - IPC command with data and pointers
+ * @cmd:       IPC command code.
+ * @sub:       IPC command sub type.
+ * @in:                input data of this IPC command.
+ * @inlen:     input data length in bytes.
+ * @out:       output data of this IPC command.
+ * @outlen:    output data length in dwords.
+ * @sptr:      data writing to SPTR register.
+ * @dptr:      data writing to DPTR register.
+ *
+ * Send an IPC command to PMC with input/output data and source/dest pointers.
+ *
+ * Return:     an IPC error code or 0 on success.
  */
 int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
                          u32 outlen, u32 dptr, u32 sptr)
@@ -278,14 +287,18 @@ int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
 }
 EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd);
 
-/*
- * intel_pmc_ipc_command
- * @cmd: command
- * @sub: sub type
- * @in: input data
- * @inlen: input length in bytes
- * @out: output data
- * @outlen: output length in dwords
+/**
+ * intel_pmc_ipc_command() -  IPC command with input/output data
+ * @cmd:       IPC command code.
+ * @sub:       IPC command sub type.
+ * @in:                input data of this IPC command.
+ * @inlen:     input data length in bytes.
+ * @out:       output data of this IPC command.
+ * @outlen:    output data length in dwords.
+ *
+ * Send an IPC command to PMC with input/output data.
+ *
+ * Return:     an IPC error code or 0 on success.
  */
 int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
                          u32 *out, u32 outlen)
@@ -480,11 +493,11 @@ static int ipc_create_punit_device(void)
        pdev->dev.parent = ipcdev.dev;
 
        res = punit_res;
-       res->start = (resource_size_t)ipcdev.punit_base;
+       res->start = ipcdev.punit_base;
        res->end = res->start + ipcdev.punit_size - 1;
 
        res = punit_res + PUNIT_RESOURCE_INTER;
-       res->start = (resource_size_t)ipcdev.punit_base2;
+       res->start = ipcdev.punit_base2;
        res->end = res->start + ipcdev.punit_size2 - 1;
 
        ret = platform_device_add_resources(pdev, punit_res,
@@ -522,15 +535,15 @@ static int ipc_create_tco_device(void)
        pdev->dev.parent = ipcdev.dev;
 
        res = tco_res + TCO_RESOURCE_ACPI_IO;
-       res->start = (resource_size_t)ipcdev.acpi_io_base + TCO_BASE_OFFSET;
+       res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
        res->end = res->start + TCO_REGS_SIZE - 1;
 
        res = tco_res + TCO_RESOURCE_SMI_EN_IO;
-       res->start = (resource_size_t)ipcdev.acpi_io_base + SMI_EN_OFFSET;
+       res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
        res->end = res->start + SMI_EN_SIZE - 1;
 
        res = tco_res + TCO_RESOURCE_GCR_MEM;
-       res->start = (resource_size_t)ipcdev.gcr_base;
+       res->start = ipcdev.gcr_base;
        res->end = res->start + ipcdev.gcr_size - 1;
 
        ret = platform_device_add_resources(pdev, tco_res, ARRAY_SIZE(tco_res));
@@ -589,7 +602,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
                return -ENXIO;
        }
        size = resource_size(res);
-       ipcdev.acpi_io_base = (void *)res->start;
+       ipcdev.acpi_io_base = res->start;
        ipcdev.acpi_io_size = size;
        dev_info(&pdev->dev, "io res: %llx %x\n",
                 (long long)res->start, (int)resource_size(res));
@@ -601,7 +614,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
                return -ENXIO;
        }
        size = resource_size(res);
-       ipcdev.punit_base = (void *)res->start;
+       ipcdev.punit_base = res->start;
        ipcdev.punit_size = size;
        dev_info(&pdev->dev, "punit data res: %llx %x\n",
                 (long long)res->start, (int)resource_size(res));
@@ -613,7 +626,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
                return -ENXIO;
        }
        size = resource_size(res);
-       ipcdev.punit_base2 = (void *)res->start;
+       ipcdev.punit_base2 = res->start;
        ipcdev.punit_size2 = size;
        dev_info(&pdev->dev, "punit interface res: %llx %x\n",
                 (long long)res->start, (int)resource_size(res));
@@ -637,7 +650,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
        }
        ipcdev.ipc_base = addr;
 
-       ipcdev.gcr_base = (void *)(res->start + size);
+       ipcdev.gcr_base = res->start + size;
        ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
        dev_info(&pdev->dev, "ipc res: %llx %x\n",
                 (long long)res->start, (int)resource_size(res));
index 001b199a8c33d3a90e6693edd6475a63bf6dc6a5..187d1086d15c3ddc4d939715cc65cd33b820409e 100644 (file)
@@ -216,13 +216,13 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
        int nc;
        u32 offset = 0;
        int err;
-       u8 cbuf[IPC_WWBUF_SIZE] = { };
+       u8 cbuf[IPC_WWBUF_SIZE];
        u32 *wbuf = (u32 *)&cbuf;
 
-       mutex_lock(&ipclock);
-
        memset(cbuf, 0, sizeof(cbuf));
 
+       mutex_lock(&ipclock);
+
        if (ipcdev.pdev == NULL) {
                mutex_unlock(&ipclock);
                return -ENODEV;
index 515f33882ab89ae27ea4d7006e818fa8b15fffb3..49c1720df59a8550cdca31735e6ef519f6b88266 100644 (file)
@@ -7,7 +7,6 @@
  *     Bjorn Helgaas <bjorn.helgaas@hp.com>
  */
 
-#include <linux/acpi.h>
 #include <linux/pnp.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -23,41 +22,25 @@ static const struct pnp_device_id pnp_dev_table[] = {
        {"", 0}
 };
 
-#ifdef CONFIG_ACPI
-static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
-{
-       u8 space_id = io ? ACPI_ADR_SPACE_SYSTEM_IO : ACPI_ADR_SPACE_SYSTEM_MEMORY;
-       return !acpi_reserve_region(start, length, space_id, IORESOURCE_BUSY, desc);
-}
-#else
-static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
-{
-       struct resource *res;
-
-       res = io ? request_region(start, length, desc) :
-               request_mem_region(start, length, desc);
-       if (res) {
-               res->flags &= ~IORESOURCE_BUSY;
-               return true;
-       }
-       return false;
-}
-#endif
-
 static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
 {
        char *regionid;
        const char *pnpid = dev_name(&dev->dev);
        resource_size_t start = r->start, end = r->end;
-       bool reserved;
+       struct resource *res;
 
        regionid = kmalloc(16, GFP_KERNEL);
        if (!regionid)
                return;
 
        snprintf(regionid, 16, "pnp %s", pnpid);
-       reserved = __reserve_range(start, end - start + 1, !!port, regionid);
-       if (!reserved)
+       if (port)
+               res = request_region(start, end - start + 1, regionid);
+       else
+               res = request_mem_region(start, end - start + 1, regionid);
+       if (res)
+               res->flags &= ~IORESOURCE_BUSY;
+       else
                kfree(regionid);
 
        /*
@@ -66,7 +49,7 @@ static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
         * have double reservations.
         */
        dev_info(&dev->dev, "%pR %s reserved\n", r,
-                reserved ? "has been" : "could not be");
+                res ? "has been" : "could not be");
 }
 
 static void reserve_resources_of_dev(struct pnp_dev *dev)
index 832932bdc977d21e84f2f8f563ce8aa937c64bc1..7fd4f511d78fd6bdc685c857e280f1581d20b035 100644 (file)
@@ -130,7 +130,7 @@ struct pm800_regulators {
                .owner  = THIS_MODULE,                                  \
                .n_voltages = ARRAY_SIZE(ldo_volt_table),               \
                .vsel_reg       = PM800_##vreg##_VOUT,                  \
-               .vsel_mask      = 0x1f,                                 \
+               .vsel_mask      = 0xf,                                  \
                .enable_reg     = PM800_##ereg,                         \
                .enable_mask    = 1 << (ebit),                          \
                .volt_table     = ldo_volt_table,                       \
index c9f72019bd689afbb4e51528932689dc097b191b..78387a6cbae59e40a6fb05fc255647cacfe3209b 100644 (file)
@@ -109,6 +109,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 static struct regulator *create_regulator(struct regulator_dev *rdev,
                                          struct device *dev,
                                          const char *supply_name);
+static void _regulator_put(struct regulator *regulator);
 
 static const char *rdev_get_name(struct regulator_dev *rdev)
 {
@@ -1105,6 +1106,9 @@ static int set_supply(struct regulator_dev *rdev,
 
        rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
 
+       if (!try_module_get(supply_rdev->owner))
+               return -ENODEV;
+
        rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
        if (rdev->supply == NULL) {
                err = -ENOMEM;
@@ -1381,9 +1385,13 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        }
 
        if (!r) {
-               dev_err(dev, "Failed to resolve %s-supply for %s\n",
-                       rdev->supply_name, rdev->desc->name);
-               return -EPROBE_DEFER;
+               if (have_full_constraints()) {
+                       r = dummy_regulator_rdev;
+               } else {
+                       dev_err(dev, "Failed to resolve %s-supply for %s\n",
+                               rdev->supply_name, rdev->desc->name);
+                       return -EPROBE_DEFER;
+               }
        }
 
        /* Recursively resolve the supply of the supply */
@@ -1398,8 +1406,11 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        /* Cascade always-on state to supply */
        if (_regulator_is_enabled(rdev)) {
                ret = regulator_enable(rdev->supply);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (rdev->supply)
+                               _regulator_put(rdev->supply);
                        return ret;
+               }
        }
 
        return 0;
index 6f2bdad8b4d8fd6ce2e552d4c44c8cf4a3ee60ba..e94ddcf97722331e3cdde0645697169a35ba8c12 100644 (file)
@@ -450,7 +450,7 @@ static struct max8973_regulator_platform_data *max8973_parse_dt(
                pdata->control_flags  |= MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE;
 
        if (of_property_read_bool(np, "maxim,enable-bias-control"))
-               pdata->control_flags  |= MAX8973_BIAS_ENABLE;
+               pdata->control_flags  |= MAX8973_CONTROL_BIAS_ENABLE;
 
        return pdata;
 }
index 326ffb55337117d6dc2a96d7fce9cea773e18a14..72fc3c32db49828ce6a2a9256ecabd01bdb034e8 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/mfd/samsung/s2mps14.h>
 #include <linux/mfd/samsung/s2mpu02.h>
 
+/* The highest number of possible regulators for supported devices. */
+#define S2MPS_REGULATOR_MAX            S2MPS13_REGULATOR_MAX
 struct s2mps11_info {
        unsigned int rdev_num;
        int ramp_delay2;
@@ -49,7 +51,7 @@ struct s2mps11_info {
         * One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether
         * the suspend mode was enabled.
         */
-       unsigned long long s2mps14_suspend_state:50;
+       DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX);
 
        /* Array of size rdev_num with GPIO-s for external sleep control */
        int *ext_control_gpio;
@@ -500,7 +502,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
        switch (s2mps11->dev_type) {
        case S2MPS13X:
        case S2MPS14X:
-               if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+               if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
                        val = S2MPS14_ENABLE_SUSPEND;
                else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
                        val = S2MPS14_ENABLE_EXT_CONTROL;
@@ -508,7 +510,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
                        val = rdev->desc->enable_mask;
                break;
        case S2MPU02:
-               if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
+               if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
                        val = S2MPU02_ENABLE_SUSPEND;
                else
                        val = rdev->desc->enable_mask;
@@ -562,7 +564,7 @@ static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
        if (ret < 0)
                return ret;
 
-       s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev));
+       set_bit(rdev_get_id(rdev), s2mps11->suspend_state);
        /*
         * Don't enable suspend mode if regulator is already disabled because
         * this would effectively for a short time turn on the regulator after
@@ -960,18 +962,22 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
        case S2MPS11X:
                s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
                regulators = s2mps11_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        case S2MPS13X:
                s2mps11->rdev_num = ARRAY_SIZE(s2mps13_regulators);
                regulators = s2mps13_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        case S2MPS14X:
                s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
                regulators = s2mps14_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        case S2MPU02:
                s2mps11->rdev_num = ARRAY_SIZE(s2mpu02_regulators);
                regulators = s2mpu02_regulators;
+               BUILD_BUG_ON(S2MPS_REGULATOR_MAX < s2mps11->rdev_num);
                break;
        default:
                dev_err(&pdev->dev, "Invalid device type: %u\n",
index 4b62d1a875e43eb09bf4631f7695f31dda9bfa6d..2b08cac62f07a5c6fed07b0598025234befe2c18 100644 (file)
@@ -88,7 +88,7 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct armada38x_rtc *rtc = dev_get_drvdata(dev);
        int ret = 0;
-       unsigned long time, flags;
+       unsigned long time;
 
        ret = rtc_tm_to_time(tm, &time);
 
index c0090b698ff363732b2e1b0a727de001bc6c26a6..eab230be5a54fdfcfd9c41f39e0d9f1cb515a9e4 100644 (file)
@@ -343,6 +343,8 @@ static int mtk_rtc_probe(struct platform_device *pdev)
                goto out_dispose_irq;
        }
 
+       device_init_wakeup(&pdev->dev, 1);
+
        rtc->rtc_dev = rtc_device_register("mt6397-rtc", &pdev->dev,
                                           &mtk_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc->rtc_dev)) {
@@ -351,8 +353,6 @@ static int mtk_rtc_probe(struct platform_device *pdev)
                goto out_free_irq;
        }
 
-       device_init_wakeup(&pdev->dev, 1);
-
        return 0;
 
 out_free_irq:
index 95bccfd3f169a8a3a167368f972cbbd08de7c869..e5225ad9c5b12fdd9d723704d66eb9ec2ff5b734 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the S/390 specific device drivers
 #
 
-obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
+obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/
 
 drivers-y += drivers/s390/built-in.o
 
index 1aec8ff0b58743214ff2ad520dea009d0a1f3f96..f73d2f579a7ef26f053eb5d314dd71e54ed60b82 100644 (file)
@@ -1862,6 +1862,33 @@ static void __dasd_device_check_expire(struct dasd_device *device)
        }
 }
 
+/*
+ * return 1 when device is not eligible for IO
+ */
+static int __dasd_device_is_unusable(struct dasd_device *device,
+                                    struct dasd_ccw_req *cqr)
+{
+       int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM);
+
+       if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+               /* dasd is being set offline. */
+               return 1;
+       }
+       if (device->stopped) {
+               if (device->stopped & mask) {
+                       /* stopped and CQR will not change that. */
+                       return 1;
+               }
+               if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags)) {
+                       /* CQR is not able to change device to
+                        * operational. */
+                       return 1;
+               }
+               /* CQR required to get device operational. */
+       }
+       return 0;
+}
+
 /*
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
@@ -1876,13 +1903,8 @@ static void __dasd_device_start_head(struct dasd_device *device)
        cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
        if (cqr->status != DASD_CQR_QUEUED)
                return;
-       /* when device is stopped, return request to previous layer
-        * exception: only the disconnect or unresumed bits are set and the
-        * cqr is a path verification request
-        */
-       if (device->stopped &&
-           !(!(device->stopped & ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM))
-             && test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))) {
+       /* if device is not usable return request to upper layer */
+       if (__dasd_device_is_unusable(device, cqr)) {
                cqr->intrc = -EAGAIN;
                cqr->status = DASD_CQR_CLEARED;
                dasd_schedule_device_bh(device);
index a2597e683e790237d45db2dfd4b4a5ad655d85e9..ee3a6faae22a0b07a8eb8c40684e9d36c825bcfe 100644 (file)
@@ -699,7 +699,8 @@ struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
                                               struct dasd_device, alias_list);
        spin_unlock_irqrestore(&lcu->lock, flags);
        alias_priv = (struct dasd_eckd_private *) alias_device->private;
-       if ((alias_priv->count < private->count) && !alias_device->stopped)
+       if ((alias_priv->count < private->count) && !alias_device->stopped &&
+           !test_bit(DASD_FLAG_OFFLINE, &alias_device->flags))
                return alias_device;
        else
                return NULL;
index aeed7969fd792ba35f89cbf3b2f26e357b20de16..7bc6df3100efa8e507641172491b9d0039b9d6dd 100644 (file)
@@ -7,6 +7,7 @@
 #define KMSG_COMPONENT "sclp_early"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/errno.h>
 #include <asm/ctl_reg.h>
 #include <asm/sclp.h>
 #include <asm/ipl.h>
index 08f1830cbfc4020e5901b9ae1f12fae518f29ac5..01bf1f5cf2e95a7f40f722f51e4df87ea257e724 100644 (file)
@@ -54,6 +54,10 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \
                   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
+static int zcrypt_hwrng_seed = 1;
+module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP);
+MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on).");
+
 static DEFINE_SPINLOCK(zcrypt_device_lock);
 static LIST_HEAD(zcrypt_device_list);
 static int zcrypt_device_count = 0;
@@ -1373,6 +1377,7 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data)
 static struct hwrng zcrypt_rng_dev = {
        .name           = "zcrypt",
        .data_read      = zcrypt_rng_data_read,
+       .quality        = 990,
 };
 
 static int zcrypt_rng_device_add(void)
@@ -1387,6 +1392,8 @@ static int zcrypt_rng_device_add(void)
                        goto out;
                }
                zcrypt_rng_buffer_index = 0;
+               if (!zcrypt_hwrng_seed)
+                       zcrypt_rng_dev.quality = 0;
                rc = hwrng_register(&zcrypt_rng_dev);
                if (rc)
                        goto out_free;
diff --git a/drivers/s390/kvm/Makefile b/drivers/s390/kvm/Makefile
deleted file mode 100644 (file)
index 241891a..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Makefile for kvm guest drivers on s390
-#
-# Copyright IBM Corp. 2008
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License (version 2 only)
-# as published by the Free Software Foundation.
-
-obj-$(CONFIG_S390_GUEST) += kvm_virtio.o virtio_ccw.o
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
deleted file mode 100644 (file)
index 53fb975..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * virtio for kvm on s390
- *
- * Copyright IBM Corp. 2008
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (version 2 only)
- * as published by the Free Software Foundation.
- *
- *    Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
- */
-
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/err.h>
-#include <linux/virtio.h>
-#include <linux/virtio_config.h>
-#include <linux/slab.h>
-#include <linux/virtio_console.h>
-#include <linux/interrupt.h>
-#include <linux/virtio_ring.h>
-#include <linux/export.h>
-#include <linux/pfn.h>
-#include <asm/io.h>
-#include <asm/kvm_para.h>
-#include <asm/kvm_virtio.h>
-#include <asm/sclp.h>
-#include <asm/setup.h>
-#include <asm/irq.h>
-
-#define VIRTIO_SUBCODE_64 0x0D00
-
-/*
- * The pointer to our (page) of device descriptions.
- */
-static void *kvm_devices;
-static struct work_struct hotplug_work;
-
-struct kvm_device {
-       struct virtio_device vdev;
-       struct kvm_device_desc *desc;
-};
-
-#define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev)
-
-/*
- * memory layout:
- * - kvm_device_descriptor
- *        struct kvm_device_desc
- * - configuration
- *        struct kvm_vqconfig
- * - feature bits
- * - config space
- */
-static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc)
-{
-       return (struct kvm_vqconfig *)(desc + 1);
-}
-
-static u8 *kvm_vq_features(const struct kvm_device_desc *desc)
-{
-       return (u8 *)(kvm_vq_config(desc) + desc->num_vq);
-}
-
-static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc)
-{
-       return kvm_vq_features(desc) + desc->feature_len * 2;
-}
-
-/*
- * The total size of the config page used by this device (incl. desc)
- */
-static unsigned desc_size(const struct kvm_device_desc *desc)
-{
-       return sizeof(*desc)
-               + desc->num_vq * sizeof(struct kvm_vqconfig)
-               + desc->feature_len * 2
-               + desc->config_len;
-}
-
-/* This gets the device's feature bits. */
-static u64 kvm_get_features(struct virtio_device *vdev)
-{
-       unsigned int i;
-       u32 features = 0;
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-       u8 *in_features = kvm_vq_features(desc);
-
-       for (i = 0; i < min(desc->feature_len * 8, 32); i++)
-               if (in_features[i / 8] & (1 << (i % 8)))
-                       features |= (1 << i);
-       return features;
-}
-
-static int kvm_finalize_features(struct virtio_device *vdev)
-{
-       unsigned int i, bits;
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-       /* Second half of bitmap is features we accept. */
-       u8 *out_features = kvm_vq_features(desc) + desc->feature_len;
-
-       /* Give virtio_ring a chance to accept features. */
-       vring_transport_features(vdev);
-
-       /* Make sure we don't have any features > 32 bits! */
-       BUG_ON((u32)vdev->features != vdev->features);
-
-       memset(out_features, 0, desc->feature_len);
-       bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
-       for (i = 0; i < bits; i++) {
-               if (__virtio_test_bit(vdev, i))
-                       out_features[i / 8] |= (1 << (i % 8));
-       }
-
-       return 0;
-}
-
-/*
- * Reading and writing elements in config space
- */
-static void kvm_get(struct virtio_device *vdev, unsigned int offset,
-                  void *buf, unsigned len)
-{
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-
-       BUG_ON(offset + len > desc->config_len);
-       memcpy(buf, kvm_vq_configspace(desc) + offset, len);
-}
-
-static void kvm_set(struct virtio_device *vdev, unsigned int offset,
-                  const void *buf, unsigned len)
-{
-       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-
-       BUG_ON(offset + len > desc->config_len);
-       memcpy(kvm_vq_configspace(desc) + offset, buf, len);
-}
-
-/*
- * The operations to get and set the status word just access
- * the status field of the device descriptor. set_status will also
- * make a hypercall to the host, to tell about status changes
- */
-static u8 kvm_get_status(struct virtio_device *vdev)
-{
-       return to_kvmdev(vdev)->desc->status;
-}
-
-static void kvm_set_status(struct virtio_device *vdev, u8 status)
-{
-       BUG_ON(!status);
-       to_kvmdev(vdev)->desc->status = status;
-       kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS,
-                      (unsigned long) to_kvmdev(vdev)->desc);
-}
-
-/*
- * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the
- * descriptor address. The Host will zero the status and all the
- * features.
- */
-static void kvm_reset(struct virtio_device *vdev)
-{
-       kvm_hypercall1(KVM_S390_VIRTIO_RESET,
-                      (unsigned long) to_kvmdev(vdev)->desc);
-}
-
-/*
- * When the virtio_ring code wants to notify the Host, it calls us here and we
- * make a hypercall.  We hand the address  of the virtqueue so the Host
- * knows which virtqueue we're talking about.
- */
-static bool kvm_notify(struct virtqueue *vq)
-{
-       long rc;
-       struct kvm_vqconfig *config = vq->priv;
-
-       rc = kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address);
-       if (rc < 0)
-               return false;
-       return true;
-}
-
-/*
- * This routine finds the first virtqueue described in the configuration of
- * this device and sets it up.
- */
-static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
-                                    unsigned index,
-                                    void (*callback)(struct virtqueue *vq),
-                                    const char *name)
-{
-       struct kvm_device *kdev = to_kvmdev(vdev);
-       struct kvm_vqconfig *config;
-       struct virtqueue *vq;
-       int err;
-
-       if (index >= kdev->desc->num_vq)
-               return ERR_PTR(-ENOENT);
-
-       if (!name)
-               return NULL;
-
-       config = kvm_vq_config(kdev->desc)+index;
-
-       err = vmem_add_mapping(config->address,
-                              vring_size(config->num,
-                                         KVM_S390_VIRTIO_RING_ALIGN));
-       if (err)
-               goto out;
-
-       vq = vring_new_virtqueue(index, config->num, KVM_S390_VIRTIO_RING_ALIGN,
-                                vdev, true, (void *) config->address,
-                                kvm_notify, callback, name);
-       if (!vq) {
-               err = -ENOMEM;
-               goto unmap;
-       }
-
-       /*
-        * register a callback token
-        * The host will sent this via the external interrupt parameter
-        */
-       config->token = (u64) vq;
-
-       vq->priv = config;
-       return vq;
-unmap:
-       vmem_remove_mapping(config->address,
-                           vring_size(config->num,
-                                      KVM_S390_VIRTIO_RING_ALIGN));
-out:
-       return ERR_PTR(err);
-}
-
-static void kvm_del_vq(struct virtqueue *vq)
-{
-       struct kvm_vqconfig *config = vq->priv;
-
-       vring_del_virtqueue(vq);
-       vmem_remove_mapping(config->address,
-                           vring_size(config->num,
-                                      KVM_S390_VIRTIO_RING_ALIGN));
-}
-
-static void kvm_del_vqs(struct virtio_device *vdev)
-{
-       struct virtqueue *vq, *n;
-
-       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
-               kvm_del_vq(vq);
-}
-
-static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-                       struct virtqueue *vqs[],
-                       vq_callback_t *callbacks[],
-                       const char *names[])
-{
-       struct kvm_device *kdev = to_kvmdev(vdev);
-       int i;
-
-       /* We must have this many virtqueues. */
-       if (nvqs > kdev->desc->num_vq)
-               return -ENOENT;
-
-       for (i = 0; i < nvqs; ++i) {
-               vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]);
-               if (IS_ERR(vqs[i]))
-                       goto error;
-       }
-       return 0;
-
-error:
-       kvm_del_vqs(vdev);
-       return PTR_ERR(vqs[i]);
-}
-
-static const char *kvm_bus_name(struct virtio_device *vdev)
-{
-       return "";
-}
-
-/*
- * The config ops structure as defined by virtio config
- */
-static const struct virtio_config_ops kvm_vq_configspace_ops = {
-       .get_features = kvm_get_features,
-       .finalize_features = kvm_finalize_features,
-       .get = kvm_get,
-       .set = kvm_set,
-       .get_status = kvm_get_status,
-       .set_status = kvm_set_status,
-       .reset = kvm_reset,
-       .find_vqs = kvm_find_vqs,
-       .del_vqs = kvm_del_vqs,
-       .bus_name = kvm_bus_name,
-};
-
-/*
- * The root device for the kvm virtio devices.
- * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2.
- */
-static struct device *kvm_root;
-
-/*
- * adds a new device and register it with virtio
- * appropriate drivers are loaded by the device model
- */
-static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset)
-{
-       struct kvm_device *kdev;
-
-       kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
-       if (!kdev) {
-               printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n",
-                      offset, d->type);
-               return;
-       }
-
-       kdev->vdev.dev.parent = kvm_root;
-       kdev->vdev.id.device = d->type;
-       kdev->vdev.config = &kvm_vq_configspace_ops;
-       kdev->desc = d;
-
-       if (register_virtio_device(&kdev->vdev) != 0) {
-               printk(KERN_ERR "Failed to register kvm device %u type %u\n",
-                      offset, d->type);
-               kfree(kdev);
-       }
-}
-
-/*
- * scan_devices() simply iterates through the device page.
- * The type 0 is reserved to mean "end of devices".
- */
-static void scan_devices(void)
-{
-       unsigned int i;
-       struct kvm_device_desc *d;
-
-       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
-               d = kvm_devices + i;
-
-               if (d->type == 0)
-                       break;
-
-               add_kvm_device(d, i);
-       }
-}
-
-/*
- * match for a kvm device with a specific desc pointer
- */
-static int match_desc(struct device *dev, void *data)
-{
-       struct virtio_device *vdev = dev_to_virtio(dev);
-       struct kvm_device *kdev = to_kvmdev(vdev);
-
-       return kdev->desc == data;
-}
-
-/*
- * hotplug_device tries to find changes in the device page.
- */
-static void hotplug_devices(struct work_struct *dummy)
-{
-       unsigned int i;
-       struct kvm_device_desc *d;
-       struct device *dev;
-
-       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
-               d = kvm_devices + i;
-
-               /* end of list */
-               if (d->type == 0)
-                       break;
-
-               /* device already exists */
-               dev = device_find_child(kvm_root, d, match_desc);
-               if (dev) {
-                       /* XXX check for hotplug remove */
-                       put_device(dev);
-                       continue;
-               }
-
-               /* new device */
-               printk(KERN_INFO "Adding new virtio device %p\n", d);
-               add_kvm_device(d, i);
-       }
-}
-
-/*
- * we emulate the request_irq behaviour on top of s390 extints
- */
-static void kvm_extint_handler(struct ext_code ext_code,
-                              unsigned int param32, unsigned long param64)
-{
-       struct virtqueue *vq;
-       u32 param;
-
-       if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64)
-               return;
-       inc_irq_stat(IRQEXT_VRT);
-
-       /* The LSB might be overloaded, we have to mask it */
-       vq = (struct virtqueue *)(param64 & ~1UL);
-
-       /* We use ext_params to decide what this interrupt means */
-       param = param32 & VIRTIO_PARAM_MASK;
-
-       switch (param) {
-       case VIRTIO_PARAM_CONFIG_CHANGED:
-               virtio_config_changed(vq->vdev);
-               break;
-       case VIRTIO_PARAM_DEV_ADD:
-               schedule_work(&hotplug_work);
-               break;
-       case VIRTIO_PARAM_VRING_INTERRUPT:
-       default:
-               vring_interrupt(0, vq);
-               break;
-       }
-}
-
-/*
- * For s390-virtio, we expect a page above main storage containing
- * the virtio configuration. Try to actually load from this area
- * in order to figure out if the host provides this page.
- */
-static int __init test_devices_support(unsigned long addr)
-{
-       int ret = -EIO;
-
-       asm volatile(
-               "0:     lura    0,%1\n"
-               "1:     xgr     %0,%0\n"
-               "2:\n"
-               EX_TABLE(0b,2b)
-               EX_TABLE(1b,2b)
-               : "+d" (ret)
-               : "a" (addr)
-               : "0", "cc");
-       return ret;
-}
-/*
- * Init function for virtio
- * devices are in a single page above top of "normal" + standby mem
- */
-static int __init kvm_devices_init(void)
-{
-       int rc;
-       unsigned long total_memory_size = sclp.rzm * sclp.rnmax;
-
-       if (!MACHINE_IS_KVM)
-               return -ENODEV;
-
-       if (test_devices_support(total_memory_size) < 0)
-               return -ENODEV;
-
-       rc = vmem_add_mapping(total_memory_size, PAGE_SIZE);
-       if (rc)
-               return rc;
-
-       kvm_devices = (void *) total_memory_size;
-
-       kvm_root = root_device_register("kvm_s390");
-       if (IS_ERR(kvm_root)) {
-               rc = PTR_ERR(kvm_root);
-               printk(KERN_ERR "Could not register kvm_s390 root device");
-               vmem_remove_mapping(total_memory_size, PAGE_SIZE);
-               return rc;
-       }
-
-       INIT_WORK(&hotplug_work, hotplug_devices);
-
-       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
-       register_external_irq(EXT_IRQ_CP_SERVICE, kvm_extint_handler);
-
-       scan_devices();
-       return 0;
-}
-
-/* code for early console output with virtio_console */
-static __init int early_put_chars(u32 vtermno, const char *buf, int count)
-{
-       char scratch[17];
-       unsigned int len = count;
-
-       if (len > sizeof(scratch) - 1)
-               len = sizeof(scratch) - 1;
-       scratch[len] = '\0';
-       memcpy(scratch, buf, len);
-       kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch));
-       return len;
-}
-
-static int __init s390_virtio_console_init(void)
-{
-       if (sclp.has_vt220 || sclp.has_linemode)
-               return -ENODEV;
-       return virtio_cons_early_init(early_put_chars);
-}
-console_initcall(s390_virtio_console_init);
-
-
-/*
- * We do this after core stuff, but before the drivers.
- */
-postcore_initcall(kvm_devices_init);
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
deleted file mode 100644 (file)
index f8d8fdb..0000000
+++ /dev/null
@@ -1,1387 +0,0 @@
-/*
- * ccw based virtio transport
- *
- * Copyright IBM Corp. 2012, 2014
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (version 2 only)
- * as published by the Free Software Foundation.
- *
- *    Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
- */
-
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/err.h>
-#include <linux/virtio.h>
-#include <linux/virtio_config.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/virtio_ring.h>
-#include <linux/pfn.h>
-#include <linux/async.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/kvm_para.h>
-#include <linux/notifier.h>
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/cio.h>
-#include <asm/ccwdev.h>
-#include <asm/virtio-ccw.h>
-#include <asm/isc.h>
-#include <asm/airq.h>
-
-/*
- * virtio related functions
- */
-
-struct vq_config_block {
-       __u16 index;
-       __u16 num;
-} __packed;
-
-#define VIRTIO_CCW_CONFIG_SIZE 0x100
-/* same as PCI config space size, should be enough for all drivers */
-
-struct virtio_ccw_device {
-       struct virtio_device vdev;
-       __u8 *status;
-       __u8 config[VIRTIO_CCW_CONFIG_SIZE];
-       struct ccw_device *cdev;
-       __u32 curr_io;
-       int err;
-       unsigned int revision; /* Transport revision */
-       wait_queue_head_t wait_q;
-       spinlock_t lock;
-       struct list_head virtqueues;
-       unsigned long indicators;
-       unsigned long indicators2;
-       struct vq_config_block *config_block;
-       bool is_thinint;
-       bool going_away;
-       bool device_lost;
-       unsigned int config_ready;
-       void *airq_info;
-};
-
-struct vq_info_block_legacy {
-       __u64 queue;
-       __u32 align;
-       __u16 index;
-       __u16 num;
-} __packed;
-
-struct vq_info_block {
-       __u64 desc;
-       __u32 res0;
-       __u16 index;
-       __u16 num;
-       __u64 avail;
-       __u64 used;
-} __packed;
-
-struct virtio_feature_desc {
-       __u32 features;
-       __u8 index;
-} __packed;
-
-struct virtio_thinint_area {
-       unsigned long summary_indicator;
-       unsigned long indicator;
-       u64 bit_nr;
-       u8 isc;
-} __packed;
-
-struct virtio_rev_info {
-       __u16 revision;
-       __u16 length;
-       __u8 data[];
-};
-
-/* the highest virtio-ccw revision we support */
-#define VIRTIO_CCW_REV_MAX 1
-
-struct virtio_ccw_vq_info {
-       struct virtqueue *vq;
-       int num;
-       void *queue;
-       union {
-               struct vq_info_block s;
-               struct vq_info_block_legacy l;
-       } *info_block;
-       int bit_nr;
-       struct list_head node;
-       long cookie;
-};
-
-#define VIRTIO_AIRQ_ISC IO_SCH_ISC /* inherit from subchannel */
-
-#define VIRTIO_IV_BITS (L1_CACHE_BYTES * 8)
-#define MAX_AIRQ_AREAS 20
-
-static int virtio_ccw_use_airq = 1;
-
-struct airq_info {
-       rwlock_t lock;
-       u8 summary_indicator;
-       struct airq_struct airq;
-       struct airq_iv *aiv;
-};
-static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
-
-#define CCW_CMD_SET_VQ 0x13
-#define CCW_CMD_VDEV_RESET 0x33
-#define CCW_CMD_SET_IND 0x43
-#define CCW_CMD_SET_CONF_IND 0x53
-#define CCW_CMD_READ_FEAT 0x12
-#define CCW_CMD_WRITE_FEAT 0x11
-#define CCW_CMD_READ_CONF 0x22
-#define CCW_CMD_WRITE_CONF 0x21
-#define CCW_CMD_WRITE_STATUS 0x31
-#define CCW_CMD_READ_VQ_CONF 0x32
-#define CCW_CMD_SET_IND_ADAPTER 0x73
-#define CCW_CMD_SET_VIRTIO_REV 0x83
-
-#define VIRTIO_CCW_DOING_SET_VQ 0x00010000
-#define VIRTIO_CCW_DOING_RESET 0x00040000
-#define VIRTIO_CCW_DOING_READ_FEAT 0x00080000
-#define VIRTIO_CCW_DOING_WRITE_FEAT 0x00100000
-#define VIRTIO_CCW_DOING_READ_CONFIG 0x00200000
-#define VIRTIO_CCW_DOING_WRITE_CONFIG 0x00400000
-#define VIRTIO_CCW_DOING_WRITE_STATUS 0x00800000
-#define VIRTIO_CCW_DOING_SET_IND 0x01000000
-#define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000
-#define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000
-#define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000
-#define VIRTIO_CCW_DOING_SET_VIRTIO_REV 0x10000000
-#define VIRTIO_CCW_INTPARM_MASK 0xffff0000
-
-static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
-{
-       return container_of(vdev, struct virtio_ccw_device, vdev);
-}
-
-static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info)
-{
-       unsigned long i, flags;
-
-       write_lock_irqsave(&info->lock, flags);
-       for (i = 0; i < airq_iv_end(info->aiv); i++) {
-               if (vq == (void *)airq_iv_get_ptr(info->aiv, i)) {
-                       airq_iv_free_bit(info->aiv, i);
-                       airq_iv_set_ptr(info->aiv, i, 0);
-                       break;
-               }
-       }
-       write_unlock_irqrestore(&info->lock, flags);
-}
-
-static void virtio_airq_handler(struct airq_struct *airq)
-{
-       struct airq_info *info = container_of(airq, struct airq_info, airq);
-       unsigned long ai;
-
-       inc_irq_stat(IRQIO_VAI);
-       read_lock(&info->lock);
-       /* Walk through indicators field, summary indicator active. */
-       for (ai = 0;;) {
-               ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
-               if (ai == -1UL)
-                       break;
-               vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
-       }
-       info->summary_indicator = 0;
-       smp_wmb();
-       /* Walk through indicators field, summary indicator not active. */
-       for (ai = 0;;) {
-               ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
-               if (ai == -1UL)
-                       break;
-               vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
-       }
-       read_unlock(&info->lock);
-}
-
-static struct airq_info *new_airq_info(void)
-{
-       struct airq_info *info;
-       int rc;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return NULL;
-       rwlock_init(&info->lock);
-       info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR);
-       if (!info->aiv) {
-               kfree(info);
-               return NULL;
-       }
-       info->airq.handler = virtio_airq_handler;
-       info->airq.lsi_ptr = &info->summary_indicator;
-       info->airq.lsi_mask = 0xff;
-       info->airq.isc = VIRTIO_AIRQ_ISC;
-       rc = register_adapter_interrupt(&info->airq);
-       if (rc) {
-               airq_iv_release(info->aiv);
-               kfree(info);
-               return NULL;
-       }
-       return info;
-}
-
-static void destroy_airq_info(struct airq_info *info)
-{
-       if (!info)
-               return;
-
-       unregister_adapter_interrupt(&info->airq);
-       airq_iv_release(info->aiv);
-       kfree(info);
-}
-
-static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
-                                       u64 *first, void **airq_info)
-{
-       int i, j;
-       struct airq_info *info;
-       unsigned long indicator_addr = 0;
-       unsigned long bit, flags;
-
-       for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) {
-               if (!airq_areas[i])
-                       airq_areas[i] = new_airq_info();
-               info = airq_areas[i];
-               if (!info)
-                       return 0;
-               write_lock_irqsave(&info->lock, flags);
-               bit = airq_iv_alloc(info->aiv, nvqs);
-               if (bit == -1UL) {
-                       /* Not enough vacancies. */
-                       write_unlock_irqrestore(&info->lock, flags);
-                       continue;
-               }
-               *first = bit;
-               *airq_info = info;
-               indicator_addr = (unsigned long)info->aiv->vector;
-               for (j = 0; j < nvqs; j++) {
-                       airq_iv_set_ptr(info->aiv, bit + j,
-                                       (unsigned long)vqs[j]);
-               }
-               write_unlock_irqrestore(&info->lock, flags);
-       }
-       return indicator_addr;
-}
-
-static void virtio_ccw_drop_indicators(struct virtio_ccw_device *vcdev)
-{
-       struct virtio_ccw_vq_info *info;
-
-       list_for_each_entry(info, &vcdev->virtqueues, node)
-               drop_airq_indicator(info->vq, vcdev->airq_info);
-}
-
-static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag)
-{
-       unsigned long flags;
-       __u32 ret;
-
-       spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
-       if (vcdev->err)
-               ret = 0;
-       else
-               ret = vcdev->curr_io & flag;
-       spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags);
-       return ret;
-}
-
-static int ccw_io_helper(struct virtio_ccw_device *vcdev,
-                        struct ccw1 *ccw, __u32 intparm)
-{
-       int ret;
-       unsigned long flags;
-       int flag = intparm & VIRTIO_CCW_INTPARM_MASK;
-
-       do {
-               spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
-               ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0);
-               if (!ret) {
-                       if (!vcdev->curr_io)
-                               vcdev->err = 0;
-                       vcdev->curr_io |= flag;
-               }
-               spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags);
-               cpu_relax();
-       } while (ret == -EBUSY);
-       wait_event(vcdev->wait_q, doing_io(vcdev, flag) == 0);
-       return ret ? ret : vcdev->err;
-}
-
-static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
-                                     struct ccw1 *ccw)
-{
-       int ret;
-       unsigned long *indicatorp = NULL;
-       struct virtio_thinint_area *thinint_area = NULL;
-       struct airq_info *airq_info = vcdev->airq_info;
-
-       if (vcdev->is_thinint) {
-               thinint_area = kzalloc(sizeof(*thinint_area),
-                                      GFP_DMA | GFP_KERNEL);
-               if (!thinint_area)
-                       return;
-               thinint_area->summary_indicator =
-                       (unsigned long) &airq_info->summary_indicator;
-               thinint_area->isc = VIRTIO_AIRQ_ISC;
-               ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
-               ccw->count = sizeof(*thinint_area);
-               ccw->cda = (__u32)(unsigned long) thinint_area;
-       } else {
-               indicatorp = kmalloc(sizeof(&vcdev->indicators),
-                                    GFP_DMA | GFP_KERNEL);
-               if (!indicatorp)
-                       return;
-               *indicatorp = 0;
-               ccw->cmd_code = CCW_CMD_SET_IND;
-               ccw->count = sizeof(vcdev->indicators);
-               ccw->cda = (__u32)(unsigned long) indicatorp;
-       }
-       /* Deregister indicators from host. */
-       vcdev->indicators = 0;
-       ccw->flags = 0;
-       ret = ccw_io_helper(vcdev, ccw,
-                           vcdev->is_thinint ?
-                           VIRTIO_CCW_DOING_SET_IND_ADAPTER :
-                           VIRTIO_CCW_DOING_SET_IND);
-       if (ret && (ret != -ENODEV))
-               dev_info(&vcdev->cdev->dev,
-                        "Failed to deregister indicators (%d)\n", ret);
-       else if (vcdev->is_thinint)
-               virtio_ccw_drop_indicators(vcdev);
-       kfree(indicatorp);
-       kfree(thinint_area);
-}
-
-static inline long do_kvm_notify(struct subchannel_id schid,
-                                unsigned long queue_index,
-                                long cookie)
-{
-       register unsigned long __nr asm("1") = KVM_S390_VIRTIO_CCW_NOTIFY;
-       register struct subchannel_id __schid asm("2") = schid;
-       register unsigned long __index asm("3") = queue_index;
-       register long __rc asm("2");
-       register long __cookie asm("4") = cookie;
-
-       asm volatile ("diag 2,4,0x500\n"
-                     : "=d" (__rc) : "d" (__nr), "d" (__schid), "d" (__index),
-                     "d"(__cookie)
-                     : "memory", "cc");
-       return __rc;
-}
-
-static bool virtio_ccw_kvm_notify(struct virtqueue *vq)
-{
-       struct virtio_ccw_vq_info *info = vq->priv;
-       struct virtio_ccw_device *vcdev;
-       struct subchannel_id schid;
-
-       vcdev = to_vc_device(info->vq->vdev);
-       ccw_device_get_schid(vcdev->cdev, &schid);
-       info->cookie = do_kvm_notify(schid, vq->index, info->cookie);
-       if (info->cookie < 0)
-               return false;
-       return true;
-}
-
-static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
-                                  struct ccw1 *ccw, int index)
-{
-       vcdev->config_block->index = index;
-       ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
-       ccw->flags = 0;
-       ccw->count = sizeof(struct vq_config_block);
-       ccw->cda = (__u32)(unsigned long)(vcdev->config_block);
-       ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
-       return vcdev->config_block->num;
-}
-
-static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev);
-       struct virtio_ccw_vq_info *info = vq->priv;
-       unsigned long flags;
-       unsigned long size;
-       int ret;
-       unsigned int index = vq->index;
-
-       /* Remove from our list. */
-       spin_lock_irqsave(&vcdev->lock, flags);
-       list_del(&info->node);
-       spin_unlock_irqrestore(&vcdev->lock, flags);
-
-       /* Release from host. */
-       if (vcdev->revision == 0) {
-               info->info_block->l.queue = 0;
-               info->info_block->l.align = 0;
-               info->info_block->l.index = index;
-               info->info_block->l.num = 0;
-               ccw->count = sizeof(info->info_block->l);
-       } else {
-               info->info_block->s.desc = 0;
-               info->info_block->s.index = index;
-               info->info_block->s.num = 0;
-               info->info_block->s.avail = 0;
-               info->info_block->s.used = 0;
-               ccw->count = sizeof(info->info_block->s);
-       }
-       ccw->cmd_code = CCW_CMD_SET_VQ;
-       ccw->flags = 0;
-       ccw->cda = (__u32)(unsigned long)(info->info_block);
-       ret = ccw_io_helper(vcdev, ccw,
-                           VIRTIO_CCW_DOING_SET_VQ | index);
-       /*
-        * -ENODEV isn't considered an error: The device is gone anyway.
-        * This may happen on device detach.
-        */
-       if (ret && (ret != -ENODEV))
-               dev_warn(&vq->vdev->dev, "Error %d while deleting queue %d",
-                        ret, index);
-
-       vring_del_virtqueue(vq);
-       size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
-       free_pages_exact(info->queue, size);
-       kfree(info->info_block);
-       kfree(info);
-}
-
-static void virtio_ccw_del_vqs(struct virtio_device *vdev)
-{
-       struct virtqueue *vq, *n;
-       struct ccw1 *ccw;
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return;
-
-       virtio_ccw_drop_indicator(vcdev, ccw);
-
-       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
-               virtio_ccw_del_vq(vq, ccw);
-
-       kfree(ccw);
-}
-
-static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
-                                            int i, vq_callback_t *callback,
-                                            const char *name,
-                                            struct ccw1 *ccw)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       int err;
-       struct virtqueue *vq = NULL;
-       struct virtio_ccw_vq_info *info;
-       unsigned long size = 0; /* silence the compiler */
-       unsigned long flags;
-
-       /* Allocate queue. */
-       info = kzalloc(sizeof(struct virtio_ccw_vq_info), GFP_KERNEL);
-       if (!info) {
-               dev_warn(&vcdev->cdev->dev, "no info\n");
-               err = -ENOMEM;
-               goto out_err;
-       }
-       info->info_block = kzalloc(sizeof(*info->info_block),
-                                  GFP_DMA | GFP_KERNEL);
-       if (!info->info_block) {
-               dev_warn(&vcdev->cdev->dev, "no info block\n");
-               err = -ENOMEM;
-               goto out_err;
-       }
-       info->num = virtio_ccw_read_vq_conf(vcdev, ccw, i);
-       size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
-       info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
-       if (info->queue == NULL) {
-               dev_warn(&vcdev->cdev->dev, "no queue\n");
-               err = -ENOMEM;
-               goto out_err;
-       }
-
-       vq = vring_new_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev,
-                                true, info->queue, virtio_ccw_kvm_notify,
-                                callback, name);
-       if (!vq) {
-               /* For now, we fail if we can't get the requested size. */
-               dev_warn(&vcdev->cdev->dev, "no vq\n");
-               err = -ENOMEM;
-               goto out_err;
-       }
-
-       /* Register it with the host. */
-       if (vcdev->revision == 0) {
-               info->info_block->l.queue = (__u64)info->queue;
-               info->info_block->l.align = KVM_VIRTIO_CCW_RING_ALIGN;
-               info->info_block->l.index = i;
-               info->info_block->l.num = info->num;
-               ccw->count = sizeof(info->info_block->l);
-       } else {
-               info->info_block->s.desc = (__u64)info->queue;
-               info->info_block->s.index = i;
-               info->info_block->s.num = info->num;
-               info->info_block->s.avail = (__u64)virtqueue_get_avail(vq);
-               info->info_block->s.used = (__u64)virtqueue_get_used(vq);
-               ccw->count = sizeof(info->info_block->s);
-       }
-       ccw->cmd_code = CCW_CMD_SET_VQ;
-       ccw->flags = 0;
-       ccw->cda = (__u32)(unsigned long)(info->info_block);
-       err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
-       if (err) {
-               dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
-               goto out_err;
-       }
-
-       info->vq = vq;
-       vq->priv = info;
-
-       /* Save it to our list. */
-       spin_lock_irqsave(&vcdev->lock, flags);
-       list_add(&info->node, &vcdev->virtqueues);
-       spin_unlock_irqrestore(&vcdev->lock, flags);
-
-       return vq;
-
-out_err:
-       if (vq)
-               vring_del_virtqueue(vq);
-       if (info) {
-               if (info->queue)
-                       free_pages_exact(info->queue, size);
-               kfree(info->info_block);
-       }
-       kfree(info);
-       return ERR_PTR(err);
-}
-
-static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
-                                          struct virtqueue *vqs[], int nvqs,
-                                          struct ccw1 *ccw)
-{
-       int ret;
-       struct virtio_thinint_area *thinint_area = NULL;
-       struct airq_info *info;
-
-       thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL);
-       if (!thinint_area) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       /* Try to get an indicator. */
-       thinint_area->indicator = get_airq_indicator(vqs, nvqs,
-                                                    &thinint_area->bit_nr,
-                                                    &vcdev->airq_info);
-       if (!thinint_area->indicator) {
-               ret = -ENOSPC;
-               goto out;
-       }
-       info = vcdev->airq_info;
-       thinint_area->summary_indicator =
-               (unsigned long) &info->summary_indicator;
-       thinint_area->isc = VIRTIO_AIRQ_ISC;
-       ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
-       ccw->flags = CCW_FLAG_SLI;
-       ccw->count = sizeof(*thinint_area);
-       ccw->cda = (__u32)(unsigned long)thinint_area;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
-       if (ret) {
-               if (ret == -EOPNOTSUPP) {
-                       /*
-                        * The host does not support adapter interrupts
-                        * for virtio-ccw, stop trying.
-                        */
-                       virtio_ccw_use_airq = 0;
-                       pr_info("Adapter interrupts unsupported on host\n");
-               } else
-                       dev_warn(&vcdev->cdev->dev,
-                                "enabling adapter interrupts = %d\n", ret);
-               virtio_ccw_drop_indicators(vcdev);
-       }
-out:
-       kfree(thinint_area);
-       return ret;
-}
-
-static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
-                              struct virtqueue *vqs[],
-                              vq_callback_t *callbacks[],
-                              const char *names[])
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       unsigned long *indicatorp = NULL;
-       int ret, i;
-       struct ccw1 *ccw;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return -ENOMEM;
-
-       for (i = 0; i < nvqs; ++i) {
-               vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i],
-                                            ccw);
-               if (IS_ERR(vqs[i])) {
-                       ret = PTR_ERR(vqs[i]);
-                       vqs[i] = NULL;
-                       goto out;
-               }
-       }
-       ret = -ENOMEM;
-       /* We need a data area under 2G to communicate. */
-       indicatorp = kmalloc(sizeof(&vcdev->indicators), GFP_DMA | GFP_KERNEL);
-       if (!indicatorp)
-               goto out;
-       *indicatorp = (unsigned long) &vcdev->indicators;
-       if (vcdev->is_thinint) {
-               ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
-               if (ret)
-                       /* no error, just fall back to legacy interrupts */
-                       vcdev->is_thinint = 0;
-       }
-       if (!vcdev->is_thinint) {
-               /* Register queue indicators with host. */
-               vcdev->indicators = 0;
-               ccw->cmd_code = CCW_CMD_SET_IND;
-               ccw->flags = 0;
-               ccw->count = sizeof(vcdev->indicators);
-               ccw->cda = (__u32)(unsigned long) indicatorp;
-               ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
-               if (ret)
-                       goto out;
-       }
-       /* Register indicators2 with host for config changes */
-       *indicatorp = (unsigned long) &vcdev->indicators2;
-       vcdev->indicators2 = 0;
-       ccw->cmd_code = CCW_CMD_SET_CONF_IND;
-       ccw->flags = 0;
-       ccw->count = sizeof(vcdev->indicators2);
-       ccw->cda = (__u32)(unsigned long) indicatorp;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
-       if (ret)
-               goto out;
-
-       kfree(indicatorp);
-       kfree(ccw);
-       return 0;
-out:
-       kfree(indicatorp);
-       kfree(ccw);
-       virtio_ccw_del_vqs(vdev);
-       return ret;
-}
-
-static void virtio_ccw_reset(struct virtio_device *vdev)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       struct ccw1 *ccw;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return;
-
-       /* Zero status bits. */
-       *vcdev->status = 0;
-
-       /* Send a reset ccw on device. */
-       ccw->cmd_code = CCW_CMD_VDEV_RESET;
-       ccw->flags = 0;
-       ccw->count = 0;
-       ccw->cda = 0;
-       ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET);
-       kfree(ccw);
-}
-
-static u64 virtio_ccw_get_features(struct virtio_device *vdev)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       struct virtio_feature_desc *features;
-       int ret;
-       u64 rc;
-       struct ccw1 *ccw;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return 0;
-
-       features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
-       if (!features) {
-               rc = 0;
-               goto out_free;
-       }
-       /* Read the feature bits from the host. */
-       features->index = 0;
-       ccw->cmd_code = CCW_CMD_READ_FEAT;
-       ccw->flags = 0;
-       ccw->count = sizeof(*features);
-       ccw->cda = (__u32)(unsigned long)features;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
-       if (ret) {
-               rc = 0;
-               goto out_free;
-       }
-
-       rc = le32_to_cpu(features->features);
-
-       if (vcdev->revision == 0)
-               goto out_free;
-
-       /* Read second half of the feature bits from the host. */
-       features->index = 1;
-       ccw->cmd_code = CCW_CMD_READ_FEAT;
-       ccw->flags = 0;
-       ccw->count = sizeof(*features);
-       ccw->cda = (__u32)(unsigned long)features;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
-       if (ret == 0)
-               rc |= (u64)le32_to_cpu(features->features) << 32;
-
-out_free:
-       kfree(features);
-       kfree(ccw);
-       return rc;
-}
-
-static int virtio_ccw_finalize_features(struct virtio_device *vdev)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       struct virtio_feature_desc *features;
-       struct ccw1 *ccw;
-       int ret;
-
-       if (vcdev->revision >= 1 &&
-           !__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
-               dev_err(&vdev->dev, "virtio: device uses revision 1 "
-                       "but does not have VIRTIO_F_VERSION_1\n");
-               return -EINVAL;
-       }
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return -ENOMEM;
-
-       features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
-       if (!features) {
-               ret = -ENOMEM;
-               goto out_free;
-       }
-       /* Give virtio_ring a chance to accept features. */
-       vring_transport_features(vdev);
-
-       features->index = 0;
-       features->features = cpu_to_le32((u32)vdev->features);
-       /* Write the first half of the feature bits to the host. */
-       ccw->cmd_code = CCW_CMD_WRITE_FEAT;
-       ccw->flags = 0;
-       ccw->count = sizeof(*features);
-       ccw->cda = (__u32)(unsigned long)features;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
-       if (ret)
-               goto out_free;
-
-       if (vcdev->revision == 0)
-               goto out_free;
-
-       features->index = 1;
-       features->features = cpu_to_le32(vdev->features >> 32);
-       /* Write the second half of the feature bits to the host. */
-       ccw->cmd_code = CCW_CMD_WRITE_FEAT;
-       ccw->flags = 0;
-       ccw->count = sizeof(*features);
-       ccw->cda = (__u32)(unsigned long)features;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
-
-out_free:
-       kfree(features);
-       kfree(ccw);
-
-       return ret;
-}
-
-static void virtio_ccw_get_config(struct virtio_device *vdev,
-                                 unsigned int offset, void *buf, unsigned len)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       int ret;
-       struct ccw1 *ccw;
-       void *config_area;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return;
-
-       config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
-       if (!config_area)
-               goto out_free;
-
-       /* Read the config area from the host. */
-       ccw->cmd_code = CCW_CMD_READ_CONF;
-       ccw->flags = 0;
-       ccw->count = offset + len;
-       ccw->cda = (__u32)(unsigned long)config_area;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG);
-       if (ret)
-               goto out_free;
-
-       memcpy(vcdev->config, config_area, offset + len);
-       if (buf)
-               memcpy(buf, &vcdev->config[offset], len);
-       if (vcdev->config_ready < offset + len)
-               vcdev->config_ready = offset + len;
-
-out_free:
-       kfree(config_area);
-       kfree(ccw);
-}
-
-static void virtio_ccw_set_config(struct virtio_device *vdev,
-                                 unsigned int offset, const void *buf,
-                                 unsigned len)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       struct ccw1 *ccw;
-       void *config_area;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return;
-
-       config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
-       if (!config_area)
-               goto out_free;
-
-       /* Make sure we don't overwrite fields. */
-       if (vcdev->config_ready < offset)
-               virtio_ccw_get_config(vdev, 0, NULL, offset);
-       memcpy(&vcdev->config[offset], buf, len);
-       /* Write the config area to the host. */
-       memcpy(config_area, vcdev->config, sizeof(vcdev->config));
-       ccw->cmd_code = CCW_CMD_WRITE_CONF;
-       ccw->flags = 0;
-       ccw->count = offset + len;
-       ccw->cda = (__u32)(unsigned long)config_area;
-       ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
-
-out_free:
-       kfree(config_area);
-       kfree(ccw);
-}
-
-static u8 virtio_ccw_get_status(struct virtio_device *vdev)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-
-       return *vcdev->status;
-}
-
-static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
-{
-       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       u8 old_status = *vcdev->status;
-       struct ccw1 *ccw;
-       int ret;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return;
-
-       /* Write the status to the host. */
-       *vcdev->status = status;
-       ccw->cmd_code = CCW_CMD_WRITE_STATUS;
-       ccw->flags = 0;
-       ccw->count = sizeof(status);
-       ccw->cda = (__u32)(unsigned long)vcdev->status;
-       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
-       /* Write failed? We assume status is unchanged. */
-       if (ret)
-               *vcdev->status = old_status;
-       kfree(ccw);
-}
-
-static struct virtio_config_ops virtio_ccw_config_ops = {
-       .get_features = virtio_ccw_get_features,
-       .finalize_features = virtio_ccw_finalize_features,
-       .get = virtio_ccw_get_config,
-       .set = virtio_ccw_set_config,
-       .get_status = virtio_ccw_get_status,
-       .set_status = virtio_ccw_set_status,
-       .reset = virtio_ccw_reset,
-       .find_vqs = virtio_ccw_find_vqs,
-       .del_vqs = virtio_ccw_del_vqs,
-};
-
-
-/*
- * ccw bus driver related functions
- */
-
-static void virtio_ccw_release_dev(struct device *_d)
-{
-       struct virtio_device *dev = container_of(_d, struct virtio_device,
-                                                dev);
-       struct virtio_ccw_device *vcdev = to_vc_device(dev);
-
-       kfree(vcdev->status);
-       kfree(vcdev->config_block);
-       kfree(vcdev);
-}
-
-static int irb_is_error(struct irb *irb)
-{
-       if (scsw_cstat(&irb->scsw) != 0)
-               return 1;
-       if (scsw_dstat(&irb->scsw) & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return 1;
-       if (scsw_cc(&irb->scsw) != 0)
-               return 1;
-       return 0;
-}
-
-static struct virtqueue *virtio_ccw_vq_by_ind(struct virtio_ccw_device *vcdev,
-                                             int index)
-{
-       struct virtio_ccw_vq_info *info;
-       unsigned long flags;
-       struct virtqueue *vq;
-
-       vq = NULL;
-       spin_lock_irqsave(&vcdev->lock, flags);
-       list_for_each_entry(info, &vcdev->virtqueues, node) {
-               if (info->vq->index == index) {
-                       vq = info->vq;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&vcdev->lock, flags);
-       return vq;
-}
-
-static void virtio_ccw_int_handler(struct ccw_device *cdev,
-                                  unsigned long intparm,
-                                  struct irb *irb)
-{
-       __u32 activity = intparm & VIRTIO_CCW_INTPARM_MASK;
-       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
-       int i;
-       struct virtqueue *vq;
-
-       if (!vcdev)
-               return;
-       /* Check if it's a notification from the host. */
-       if ((intparm == 0) &&
-           (scsw_stctl(&irb->scsw) ==
-            (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) {
-               /* OK */
-       }
-       if (irb_is_error(irb)) {
-               /* Command reject? */
-               if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
-                   (irb->ecw[0] & SNS0_CMD_REJECT))
-                       vcdev->err = -EOPNOTSUPP;
-               else
-                       /* Map everything else to -EIO. */
-                       vcdev->err = -EIO;
-       }
-       if (vcdev->curr_io & activity) {
-               switch (activity) {
-               case VIRTIO_CCW_DOING_READ_FEAT:
-               case VIRTIO_CCW_DOING_WRITE_FEAT:
-               case VIRTIO_CCW_DOING_READ_CONFIG:
-               case VIRTIO_CCW_DOING_WRITE_CONFIG:
-               case VIRTIO_CCW_DOING_WRITE_STATUS:
-               case VIRTIO_CCW_DOING_SET_VQ:
-               case VIRTIO_CCW_DOING_SET_IND:
-               case VIRTIO_CCW_DOING_SET_CONF_IND:
-               case VIRTIO_CCW_DOING_RESET:
-               case VIRTIO_CCW_DOING_READ_VQ_CONF:
-               case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
-               case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
-                       vcdev->curr_io &= ~activity;
-                       wake_up(&vcdev->wait_q);
-                       break;
-               default:
-                       /* don't know what to do... */
-                       dev_warn(&cdev->dev, "Suspicious activity '%08x'\n",
-                                activity);
-                       WARN_ON(1);
-                       break;
-               }
-       }
-       for_each_set_bit(i, &vcdev->indicators,
-                        sizeof(vcdev->indicators) * BITS_PER_BYTE) {
-               /* The bit clear must happen before the vring kick. */
-               clear_bit(i, &vcdev->indicators);
-               barrier();
-               vq = virtio_ccw_vq_by_ind(vcdev, i);
-               vring_interrupt(0, vq);
-       }
-       if (test_bit(0, &vcdev->indicators2)) {
-               virtio_config_changed(&vcdev->vdev);
-               clear_bit(0, &vcdev->indicators2);
-       }
-}
-
-/*
- * We usually want to autoonline all devices, but give the admin
- * a way to exempt devices from this.
- */
-#define __DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
-                    (8*sizeof(long)))
-static unsigned long devs_no_auto[__MAX_SSID + 1][__DEV_WORDS];
-
-static char *no_auto = "";
-
-module_param(no_auto, charp, 0444);
-MODULE_PARM_DESC(no_auto, "list of ccw bus id ranges not to be auto-onlined");
-
-static int virtio_ccw_check_autoonline(struct ccw_device *cdev)
-{
-       struct ccw_dev_id id;
-
-       ccw_device_get_id(cdev, &id);
-       if (test_bit(id.devno, devs_no_auto[id.ssid]))
-               return 0;
-       return 1;
-}
-
-static void virtio_ccw_auto_online(void *data, async_cookie_t cookie)
-{
-       struct ccw_device *cdev = data;
-       int ret;
-
-       ret = ccw_device_set_online(cdev);
-       if (ret)
-               dev_warn(&cdev->dev, "Failed to set online: %d\n", ret);
-}
-
-static int virtio_ccw_probe(struct ccw_device *cdev)
-{
-       cdev->handler = virtio_ccw_int_handler;
-
-       if (virtio_ccw_check_autoonline(cdev))
-               async_schedule(virtio_ccw_auto_online, cdev);
-       return 0;
-}
-
-static struct virtio_ccw_device *virtio_grab_drvdata(struct ccw_device *cdev)
-{
-       unsigned long flags;
-       struct virtio_ccw_device *vcdev;
-
-       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       vcdev = dev_get_drvdata(&cdev->dev);
-       if (!vcdev || vcdev->going_away) {
-               spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-               return NULL;
-       }
-       vcdev->going_away = true;
-       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-       return vcdev;
-}
-
-static void virtio_ccw_remove(struct ccw_device *cdev)
-{
-       unsigned long flags;
-       struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
-
-       if (vcdev && cdev->online) {
-               if (vcdev->device_lost)
-                       virtio_break_device(&vcdev->vdev);
-               unregister_virtio_device(&vcdev->vdev);
-               spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-               dev_set_drvdata(&cdev->dev, NULL);
-               spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-       }
-       cdev->handler = NULL;
-}
-
-static int virtio_ccw_offline(struct ccw_device *cdev)
-{
-       unsigned long flags;
-       struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
-
-       if (!vcdev)
-               return 0;
-       if (vcdev->device_lost)
-               virtio_break_device(&vcdev->vdev);
-       unregister_virtio_device(&vcdev->vdev);
-       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       dev_set_drvdata(&cdev->dev, NULL);
-       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-       return 0;
-}
-
-static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
-{
-       struct virtio_rev_info *rev;
-       struct ccw1 *ccw;
-       int ret;
-
-       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
-       if (!ccw)
-               return -ENOMEM;
-       rev = kzalloc(sizeof(*rev), GFP_DMA | GFP_KERNEL);
-       if (!rev) {
-               kfree(ccw);
-               return -ENOMEM;
-       }
-
-       /* Set transport revision */
-       ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV;
-       ccw->flags = 0;
-       ccw->count = sizeof(*rev);
-       ccw->cda = (__u32)(unsigned long)rev;
-
-       vcdev->revision = VIRTIO_CCW_REV_MAX;
-       do {
-               rev->revision = vcdev->revision;
-               /* none of our supported revisions carry payload */
-               rev->length = 0;
-               ret = ccw_io_helper(vcdev, ccw,
-                                   VIRTIO_CCW_DOING_SET_VIRTIO_REV);
-               if (ret == -EOPNOTSUPP) {
-                       if (vcdev->revision == 0)
-                               /*
-                                * The host device does not support setting
-                                * the revision: let's operate it in legacy
-                                * mode.
-                                */
-                               ret = 0;
-                       else
-                               vcdev->revision--;
-               }
-       } while (ret == -EOPNOTSUPP);
-
-       kfree(ccw);
-       kfree(rev);
-       return ret;
-}
-
-static int virtio_ccw_online(struct ccw_device *cdev)
-{
-       int ret;
-       struct virtio_ccw_device *vcdev;
-       unsigned long flags;
-
-       vcdev = kzalloc(sizeof(*vcdev), GFP_KERNEL);
-       if (!vcdev) {
-               dev_warn(&cdev->dev, "Could not get memory for virtio\n");
-               ret = -ENOMEM;
-               goto out_free;
-       }
-       vcdev->config_block = kzalloc(sizeof(*vcdev->config_block),
-                                  GFP_DMA | GFP_KERNEL);
-       if (!vcdev->config_block) {
-               ret = -ENOMEM;
-               goto out_free;
-       }
-       vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL);
-       if (!vcdev->status) {
-               ret = -ENOMEM;
-               goto out_free;
-       }
-
-       vcdev->is_thinint = virtio_ccw_use_airq; /* at least try */
-
-       vcdev->vdev.dev.parent = &cdev->dev;
-       vcdev->vdev.dev.release = virtio_ccw_release_dev;
-       vcdev->vdev.config = &virtio_ccw_config_ops;
-       vcdev->cdev = cdev;
-       init_waitqueue_head(&vcdev->wait_q);
-       INIT_LIST_HEAD(&vcdev->virtqueues);
-       spin_lock_init(&vcdev->lock);
-
-       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       dev_set_drvdata(&cdev->dev, vcdev);
-       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-       vcdev->vdev.id.vendor = cdev->id.cu_type;
-       vcdev->vdev.id.device = cdev->id.cu_model;
-
-       ret = virtio_ccw_set_transport_rev(vcdev);
-       if (ret)
-               goto out_free;
-
-       ret = register_virtio_device(&vcdev->vdev);
-       if (ret) {
-               dev_warn(&cdev->dev, "Failed to register virtio device: %d\n",
-                        ret);
-               goto out_put;
-       }
-       return 0;
-out_put:
-       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       dev_set_drvdata(&cdev->dev, NULL);
-       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-       put_device(&vcdev->vdev.dev);
-       return ret;
-out_free:
-       if (vcdev) {
-               kfree(vcdev->status);
-               kfree(vcdev->config_block);
-       }
-       kfree(vcdev);
-       return ret;
-}
-
-static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event)
-{
-       int rc;
-       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
-
-       /*
-        * Make sure vcdev is set
-        * i.e. set_offline/remove callback not already running
-        */
-       if (!vcdev)
-               return NOTIFY_DONE;
-
-       switch (event) {
-       case CIO_GONE:
-               vcdev->device_lost = true;
-               rc = NOTIFY_DONE;
-               break;
-       default:
-               rc = NOTIFY_DONE;
-               break;
-       }
-       return rc;
-}
-
-static struct ccw_device_id virtio_ids[] = {
-       { CCW_DEVICE(0x3832, 0) },
-       {},
-};
-MODULE_DEVICE_TABLE(ccw, virtio_ids);
-
-static struct ccw_driver virtio_ccw_driver = {
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "virtio_ccw",
-       },
-       .ids = virtio_ids,
-       .probe = virtio_ccw_probe,
-       .remove = virtio_ccw_remove,
-       .set_offline = virtio_ccw_offline,
-       .set_online = virtio_ccw_online,
-       .notify = virtio_ccw_cio_notify,
-       .int_class = IRQIO_VIR,
-};
-
-static int __init pure_hex(char **cp, unsigned int *val, int min_digit,
-                          int max_digit, int max_val)
-{
-       int diff;
-
-       diff = 0;
-       *val = 0;
-
-       while (diff <= max_digit) {
-               int value = hex_to_bin(**cp);
-
-               if (value < 0)
-                       break;
-               *val = *val * 16 + value;
-               (*cp)++;
-               diff++;
-       }
-
-       if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
-               return 1;
-
-       return 0;
-}
-
-static int __init parse_busid(char *str, unsigned int *cssid,
-                             unsigned int *ssid, unsigned int *devno)
-{
-       char *str_work;
-       int rc, ret;
-
-       rc = 1;
-
-       if (*str == '\0')
-               goto out;
-
-       str_work = str;
-       ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
-       if (ret || (str_work[0] != '.'))
-               goto out;
-       str_work++;
-       ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
-       if (ret || (str_work[0] != '.'))
-               goto out;
-       str_work++;
-       ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
-       if (ret || (str_work[0] != '\0'))
-               goto out;
-
-       rc = 0;
-out:
-       return rc;
-}
-
-static void __init no_auto_parse(void)
-{
-       unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
-       char *parm, *str;
-       int rc;
-
-       str = no_auto;
-       while ((parm = strsep(&str, ","))) {
-               rc = parse_busid(strsep(&parm, "-"), &from_cssid,
-                                &from_ssid, &from);
-               if (rc)
-                       continue;
-               if (parm != NULL) {
-                       rc = parse_busid(parm, &to_cssid,
-                                        &to_ssid, &to);
-                       if ((from_ssid > to_ssid) ||
-                           ((from_ssid == to_ssid) && (from > to)))
-                               rc = -EINVAL;
-               } else {
-                       to_cssid = from_cssid;
-                       to_ssid = from_ssid;
-                       to = from;
-               }
-               if (rc)
-                       continue;
-               while ((from_ssid < to_ssid) ||
-                      ((from_ssid == to_ssid) && (from <= to))) {
-                       set_bit(from, devs_no_auto[from_ssid]);
-                       from++;
-                       if (from > __MAX_SUBCHANNEL) {
-                               from_ssid++;
-                               from = 0;
-                       }
-               }
-       }
-}
-
-static int __init virtio_ccw_init(void)
-{
-       /* parse no_auto string before we do anything further */
-       no_auto_parse();
-       return ccw_driver_register(&virtio_ccw_driver);
-}
-module_init(virtio_ccw_init);
-
-static void __exit virtio_ccw_exit(void)
-{
-       int i;
-
-       ccw_driver_unregister(&virtio_ccw_driver);
-       for (i = 0; i < MAX_AIRQ_AREAS; i++)
-               destroy_airq_info(airq_areas[i]);
-}
-module_exit(virtio_ccw_exit);
diff --git a/drivers/s390/virtio/Makefile b/drivers/s390/virtio/Makefile
new file mode 100644 (file)
index 0000000..241891a
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile for kvm guest drivers on s390
+#
+# Copyright IBM Corp. 2008
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (version 2 only)
+# as published by the Free Software Foundation.
+
+obj-$(CONFIG_S390_GUEST) += kvm_virtio.o virtio_ccw.o
diff --git a/drivers/s390/virtio/kvm_virtio.c b/drivers/s390/virtio/kvm_virtio.c
new file mode 100644 (file)
index 0000000..53fb975
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * virtio for kvm on s390
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/slab.h>
+#include <linux/virtio_console.h>
+#include <linux/interrupt.h>
+#include <linux/virtio_ring.h>
+#include <linux/export.h>
+#include <linux/pfn.h>
+#include <asm/io.h>
+#include <asm/kvm_para.h>
+#include <asm/kvm_virtio.h>
+#include <asm/sclp.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+#define VIRTIO_SUBCODE_64 0x0D00
+
+/*
+ * The pointer to our (page) of device descriptions.
+ */
+static void *kvm_devices;
+static struct work_struct hotplug_work;
+
+struct kvm_device {
+       struct virtio_device vdev;
+       struct kvm_device_desc *desc;
+};
+
+#define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev)
+
+/*
+ * memory layout:
+ * - kvm_device_descriptor
+ *        struct kvm_device_desc
+ * - configuration
+ *        struct kvm_vqconfig
+ * - feature bits
+ * - config space
+ */
+static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc)
+{
+       return (struct kvm_vqconfig *)(desc + 1);
+}
+
+static u8 *kvm_vq_features(const struct kvm_device_desc *desc)
+{
+       return (u8 *)(kvm_vq_config(desc) + desc->num_vq);
+}
+
+static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc)
+{
+       return kvm_vq_features(desc) + desc->feature_len * 2;
+}
+
+/*
+ * The total size of the config page used by this device (incl. desc)
+ */
+static unsigned desc_size(const struct kvm_device_desc *desc)
+{
+       return sizeof(*desc)
+               + desc->num_vq * sizeof(struct kvm_vqconfig)
+               + desc->feature_len * 2
+               + desc->config_len;
+}
+
+/* This gets the device's feature bits. */
+static u64 kvm_get_features(struct virtio_device *vdev)
+{
+       unsigned int i;
+       u32 features = 0;
+       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+       u8 *in_features = kvm_vq_features(desc);
+
+       for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+               if (in_features[i / 8] & (1 << (i % 8)))
+                       features |= (1 << i);
+       return features;
+}
+
+static int kvm_finalize_features(struct virtio_device *vdev)
+{
+       unsigned int i, bits;
+       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+       /* Second half of bitmap is features we accept. */
+       u8 *out_features = kvm_vq_features(desc) + desc->feature_len;
+
+       /* Give virtio_ring a chance to accept features. */
+       vring_transport_features(vdev);
+
+       /* Make sure we don't have any features > 32 bits! */
+       BUG_ON((u32)vdev->features != vdev->features);
+
+       memset(out_features, 0, desc->feature_len);
+       bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
+       for (i = 0; i < bits; i++) {
+               if (__virtio_test_bit(vdev, i))
+                       out_features[i / 8] |= (1 << (i % 8));
+       }
+
+       return 0;
+}
+
+/*
+ * Reading and writing elements in config space
+ */
+static void kvm_get(struct virtio_device *vdev, unsigned int offset,
+                  void *buf, unsigned len)
+{
+       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+
+       BUG_ON(offset + len > desc->config_len);
+       memcpy(buf, kvm_vq_configspace(desc) + offset, len);
+}
+
+static void kvm_set(struct virtio_device *vdev, unsigned int offset,
+                  const void *buf, unsigned len)
+{
+       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+
+       BUG_ON(offset + len > desc->config_len);
+       memcpy(kvm_vq_configspace(desc) + offset, buf, len);
+}
+
+/*
+ * The operations to get and set the status word just access
+ * the status field of the device descriptor. set_status will also
+ * make a hypercall to the host, to tell about status changes
+ */
+static u8 kvm_get_status(struct virtio_device *vdev)
+{
+       return to_kvmdev(vdev)->desc->status;
+}
+
+static void kvm_set_status(struct virtio_device *vdev, u8 status)
+{
+       BUG_ON(!status);
+       to_kvmdev(vdev)->desc->status = status;
+       kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS,
+                      (unsigned long) to_kvmdev(vdev)->desc);
+}
+
+/*
+ * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the
+ * descriptor address. The Host will zero the status and all the
+ * features.
+ */
+static void kvm_reset(struct virtio_device *vdev)
+{
+       kvm_hypercall1(KVM_S390_VIRTIO_RESET,
+                      (unsigned long) to_kvmdev(vdev)->desc);
+}
+
+/*
+ * When the virtio_ring code wants to notify the Host, it calls us here and we
+ * make a hypercall.  We hand the address  of the virtqueue so the Host
+ * knows which virtqueue we're talking about.
+ */
+static bool kvm_notify(struct virtqueue *vq)
+{
+       long rc;
+       struct kvm_vqconfig *config = vq->priv;
+
+       rc = kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address);
+       if (rc < 0)
+               return false;
+       return true;
+}
+
+/*
+ * This routine finds the first virtqueue described in the configuration of
+ * this device and sets it up.
+ */
+static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
+                                    unsigned index,
+                                    void (*callback)(struct virtqueue *vq),
+                                    const char *name)
+{
+       struct kvm_device *kdev = to_kvmdev(vdev);
+       struct kvm_vqconfig *config;
+       struct virtqueue *vq;
+       int err;
+
+       if (index >= kdev->desc->num_vq)
+               return ERR_PTR(-ENOENT);
+
+       if (!name)
+               return NULL;
+
+       config = kvm_vq_config(kdev->desc)+index;
+
+       err = vmem_add_mapping(config->address,
+                              vring_size(config->num,
+                                         KVM_S390_VIRTIO_RING_ALIGN));
+       if (err)
+               goto out;
+
+       vq = vring_new_virtqueue(index, config->num, KVM_S390_VIRTIO_RING_ALIGN,
+                                vdev, true, (void *) config->address,
+                                kvm_notify, callback, name);
+       if (!vq) {
+               err = -ENOMEM;
+               goto unmap;
+       }
+
+       /*
+        * register a callback token
+        * The host will sent this via the external interrupt parameter
+        */
+       config->token = (u64) vq;
+
+       vq->priv = config;
+       return vq;
+unmap:
+       vmem_remove_mapping(config->address,
+                           vring_size(config->num,
+                                      KVM_S390_VIRTIO_RING_ALIGN));
+out:
+       return ERR_PTR(err);
+}
+
+static void kvm_del_vq(struct virtqueue *vq)
+{
+       struct kvm_vqconfig *config = vq->priv;
+
+       vring_del_virtqueue(vq);
+       vmem_remove_mapping(config->address,
+                           vring_size(config->num,
+                                      KVM_S390_VIRTIO_RING_ALIGN));
+}
+
+static void kvm_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+               kvm_del_vq(vq);
+}
+
+static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                       struct virtqueue *vqs[],
+                       vq_callback_t *callbacks[],
+                       const char *names[])
+{
+       struct kvm_device *kdev = to_kvmdev(vdev);
+       int i;
+
+       /* We must have this many virtqueues. */
+       if (nvqs > kdev->desc->num_vq)
+               return -ENOENT;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]);
+               if (IS_ERR(vqs[i]))
+                       goto error;
+       }
+       return 0;
+
+error:
+       kvm_del_vqs(vdev);
+       return PTR_ERR(vqs[i]);
+}
+
+static const char *kvm_bus_name(struct virtio_device *vdev)
+{
+       return "";
+}
+
+/*
+ * The config ops structure as defined by virtio config
+ */
+static const struct virtio_config_ops kvm_vq_configspace_ops = {
+       .get_features = kvm_get_features,
+       .finalize_features = kvm_finalize_features,
+       .get = kvm_get,
+       .set = kvm_set,
+       .get_status = kvm_get_status,
+       .set_status = kvm_set_status,
+       .reset = kvm_reset,
+       .find_vqs = kvm_find_vqs,
+       .del_vqs = kvm_del_vqs,
+       .bus_name = kvm_bus_name,
+};
+
+/*
+ * The root device for the kvm virtio devices.
+ * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2.
+ */
+static struct device *kvm_root;
+
+/*
+ * adds a new device and register it with virtio
+ * appropriate drivers are loaded by the device model
+ */
+static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset)
+{
+       struct kvm_device *kdev;
+
+       kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
+       if (!kdev) {
+               printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n",
+                      offset, d->type);
+               return;
+       }
+
+       kdev->vdev.dev.parent = kvm_root;
+       kdev->vdev.id.device = d->type;
+       kdev->vdev.config = &kvm_vq_configspace_ops;
+       kdev->desc = d;
+
+       if (register_virtio_device(&kdev->vdev) != 0) {
+               printk(KERN_ERR "Failed to register kvm device %u type %u\n",
+                      offset, d->type);
+               kfree(kdev);
+       }
+}
+
+/*
+ * scan_devices() simply iterates through the device page.
+ * The type 0 is reserved to mean "end of devices".
+ */
+static void scan_devices(void)
+{
+       unsigned int i;
+       struct kvm_device_desc *d;
+
+       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
+               d = kvm_devices + i;
+
+               if (d->type == 0)
+                       break;
+
+               add_kvm_device(d, i);
+       }
+}
+
+/*
+ * match for a kvm device with a specific desc pointer
+ */
+static int match_desc(struct device *dev, void *data)
+{
+       struct virtio_device *vdev = dev_to_virtio(dev);
+       struct kvm_device *kdev = to_kvmdev(vdev);
+
+       return kdev->desc == data;
+}
+
+/*
+ * hotplug_device tries to find changes in the device page.
+ */
+static void hotplug_devices(struct work_struct *dummy)
+{
+       unsigned int i;
+       struct kvm_device_desc *d;
+       struct device *dev;
+
+       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
+               d = kvm_devices + i;
+
+               /* end of list */
+               if (d->type == 0)
+                       break;
+
+               /* device already exists */
+               dev = device_find_child(kvm_root, d, match_desc);
+               if (dev) {
+                       /* XXX check for hotplug remove */
+                       put_device(dev);
+                       continue;
+               }
+
+               /* new device */
+               printk(KERN_INFO "Adding new virtio device %p\n", d);
+               add_kvm_device(d, i);
+       }
+}
+
+/*
+ * we emulate the request_irq behaviour on top of s390 extints
+ */
+static void kvm_extint_handler(struct ext_code ext_code,
+                              unsigned int param32, unsigned long param64)
+{
+       struct virtqueue *vq;
+       u32 param;
+
+       if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64)
+               return;
+       inc_irq_stat(IRQEXT_VRT);
+
+       /* The LSB might be overloaded, we have to mask it */
+       vq = (struct virtqueue *)(param64 & ~1UL);
+
+       /* We use ext_params to decide what this interrupt means */
+       param = param32 & VIRTIO_PARAM_MASK;
+
+       switch (param) {
+       case VIRTIO_PARAM_CONFIG_CHANGED:
+               virtio_config_changed(vq->vdev);
+               break;
+       case VIRTIO_PARAM_DEV_ADD:
+               schedule_work(&hotplug_work);
+               break;
+       case VIRTIO_PARAM_VRING_INTERRUPT:
+       default:
+               vring_interrupt(0, vq);
+               break;
+       }
+}
+
+/*
+ * For s390-virtio, we expect a page above main storage containing
+ * the virtio configuration. Try to actually load from this area
+ * in order to figure out if the host provides this page.
+ */
+static int __init test_devices_support(unsigned long addr)
+{
+       int ret = -EIO;
+
+       asm volatile(
+               "0:     lura    0,%1\n"
+               "1:     xgr     %0,%0\n"
+               "2:\n"
+               EX_TABLE(0b,2b)
+               EX_TABLE(1b,2b)
+               : "+d" (ret)
+               : "a" (addr)
+               : "0", "cc");
+       return ret;
+}
+/*
+ * Init function for virtio
+ * devices are in a single page above top of "normal" + standby mem
+ */
+static int __init kvm_devices_init(void)
+{
+       int rc;
+       unsigned long total_memory_size = sclp.rzm * sclp.rnmax;
+
+       if (!MACHINE_IS_KVM)
+               return -ENODEV;
+
+       if (test_devices_support(total_memory_size) < 0)
+               return -ENODEV;
+
+       rc = vmem_add_mapping(total_memory_size, PAGE_SIZE);
+       if (rc)
+               return rc;
+
+       kvm_devices = (void *) total_memory_size;
+
+       kvm_root = root_device_register("kvm_s390");
+       if (IS_ERR(kvm_root)) {
+               rc = PTR_ERR(kvm_root);
+               printk(KERN_ERR "Could not register kvm_s390 root device");
+               vmem_remove_mapping(total_memory_size, PAGE_SIZE);
+               return rc;
+       }
+
+       INIT_WORK(&hotplug_work, hotplug_devices);
+
+       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
+       register_external_irq(EXT_IRQ_CP_SERVICE, kvm_extint_handler);
+
+       scan_devices();
+       return 0;
+}
+
+/* code for early console output with virtio_console */
+static __init int early_put_chars(u32 vtermno, const char *buf, int count)
+{
+       char scratch[17];
+       unsigned int len = count;
+
+       if (len > sizeof(scratch) - 1)
+               len = sizeof(scratch) - 1;
+       scratch[len] = '\0';
+       memcpy(scratch, buf, len);
+       kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch));
+       return len;
+}
+
+static int __init s390_virtio_console_init(void)
+{
+       if (sclp.has_vt220 || sclp.has_linemode)
+               return -ENODEV;
+       return virtio_cons_early_init(early_put_chars);
+}
+console_initcall(s390_virtio_console_init);
+
+
+/*
+ * We do this after core stuff, but before the drivers.
+ */
+postcore_initcall(kvm_devices_init);
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
new file mode 100644 (file)
index 0000000..f8d8fdb
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ * ccw based virtio transport
+ *
+ * Copyright IBM Corp. 2012, 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ *    Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/virtio_ring.h>
+#include <linux/pfn.h>
+#include <linux/async.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/kvm_para.h>
+#include <linux/notifier.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/cio.h>
+#include <asm/ccwdev.h>
+#include <asm/virtio-ccw.h>
+#include <asm/isc.h>
+#include <asm/airq.h>
+
+/*
+ * virtio related functions
+ */
+
+struct vq_config_block {
+       __u16 index;
+       __u16 num;
+} __packed;
+
+#define VIRTIO_CCW_CONFIG_SIZE 0x100
+/* same as PCI config space size, should be enough for all drivers */
+
+struct virtio_ccw_device {
+       struct virtio_device vdev;
+       __u8 *status;
+       __u8 config[VIRTIO_CCW_CONFIG_SIZE];
+       struct ccw_device *cdev;
+       __u32 curr_io;
+       int err;
+       unsigned int revision; /* Transport revision */
+       wait_queue_head_t wait_q;
+       spinlock_t lock;
+       struct list_head virtqueues;
+       unsigned long indicators;
+       unsigned long indicators2;
+       struct vq_config_block *config_block;
+       bool is_thinint;
+       bool going_away;
+       bool device_lost;
+       unsigned int config_ready;
+       void *airq_info;
+};
+
+struct vq_info_block_legacy {
+       __u64 queue;
+       __u32 align;
+       __u16 index;
+       __u16 num;
+} __packed;
+
+struct vq_info_block {
+       __u64 desc;
+       __u32 res0;
+       __u16 index;
+       __u16 num;
+       __u64 avail;
+       __u64 used;
+} __packed;
+
+struct virtio_feature_desc {
+       __u32 features;
+       __u8 index;
+} __packed;
+
+struct virtio_thinint_area {
+       unsigned long summary_indicator;
+       unsigned long indicator;
+       u64 bit_nr;
+       u8 isc;
+} __packed;
+
+struct virtio_rev_info {
+       __u16 revision;
+       __u16 length;
+       __u8 data[];
+};
+
+/* the highest virtio-ccw revision we support */
+#define VIRTIO_CCW_REV_MAX 1
+
+struct virtio_ccw_vq_info {
+       struct virtqueue *vq;
+       int num;
+       void *queue;
+       union {
+               struct vq_info_block s;
+               struct vq_info_block_legacy l;
+       } *info_block;
+       int bit_nr;
+       struct list_head node;
+       long cookie;
+};
+
+#define VIRTIO_AIRQ_ISC IO_SCH_ISC /* inherit from subchannel */
+
+#define VIRTIO_IV_BITS (L1_CACHE_BYTES * 8)
+#define MAX_AIRQ_AREAS 20
+
+static int virtio_ccw_use_airq = 1;
+
+struct airq_info {
+       rwlock_t lock;
+       u8 summary_indicator;
+       struct airq_struct airq;
+       struct airq_iv *aiv;
+};
+static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
+
+#define CCW_CMD_SET_VQ 0x13
+#define CCW_CMD_VDEV_RESET 0x33
+#define CCW_CMD_SET_IND 0x43
+#define CCW_CMD_SET_CONF_IND 0x53
+#define CCW_CMD_READ_FEAT 0x12
+#define CCW_CMD_WRITE_FEAT 0x11
+#define CCW_CMD_READ_CONF 0x22
+#define CCW_CMD_WRITE_CONF 0x21
+#define CCW_CMD_WRITE_STATUS 0x31
+#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_SET_IND_ADAPTER 0x73
+#define CCW_CMD_SET_VIRTIO_REV 0x83
+
+#define VIRTIO_CCW_DOING_SET_VQ 0x00010000
+#define VIRTIO_CCW_DOING_RESET 0x00040000
+#define VIRTIO_CCW_DOING_READ_FEAT 0x00080000
+#define VIRTIO_CCW_DOING_WRITE_FEAT 0x00100000
+#define VIRTIO_CCW_DOING_READ_CONFIG 0x00200000
+#define VIRTIO_CCW_DOING_WRITE_CONFIG 0x00400000
+#define VIRTIO_CCW_DOING_WRITE_STATUS 0x00800000
+#define VIRTIO_CCW_DOING_SET_IND 0x01000000
+#define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000
+#define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000
+#define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000
+#define VIRTIO_CCW_DOING_SET_VIRTIO_REV 0x10000000
+#define VIRTIO_CCW_INTPARM_MASK 0xffff0000
+
+static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
+{
+       return container_of(vdev, struct virtio_ccw_device, vdev);
+}
+
+static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info)
+{
+       unsigned long i, flags;
+
+       write_lock_irqsave(&info->lock, flags);
+       for (i = 0; i < airq_iv_end(info->aiv); i++) {
+               if (vq == (void *)airq_iv_get_ptr(info->aiv, i)) {
+                       airq_iv_free_bit(info->aiv, i);
+                       airq_iv_set_ptr(info->aiv, i, 0);
+                       break;
+               }
+       }
+       write_unlock_irqrestore(&info->lock, flags);
+}
+
+static void virtio_airq_handler(struct airq_struct *airq)
+{
+       struct airq_info *info = container_of(airq, struct airq_info, airq);
+       unsigned long ai;
+
+       inc_irq_stat(IRQIO_VAI);
+       read_lock(&info->lock);
+       /* Walk through indicators field, summary indicator active. */
+       for (ai = 0;;) {
+               ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
+               if (ai == -1UL)
+                       break;
+               vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
+       }
+       info->summary_indicator = 0;
+       smp_wmb();
+       /* Walk through indicators field, summary indicator not active. */
+       for (ai = 0;;) {
+               ai = airq_iv_scan(info->aiv, ai, airq_iv_end(info->aiv));
+               if (ai == -1UL)
+                       break;
+               vring_interrupt(0, (void *)airq_iv_get_ptr(info->aiv, ai));
+       }
+       read_unlock(&info->lock);
+}
+
+static struct airq_info *new_airq_info(void)
+{
+       struct airq_info *info;
+       int rc;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return NULL;
+       rwlock_init(&info->lock);
+       info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR);
+       if (!info->aiv) {
+               kfree(info);
+               return NULL;
+       }
+       info->airq.handler = virtio_airq_handler;
+       info->airq.lsi_ptr = &info->summary_indicator;
+       info->airq.lsi_mask = 0xff;
+       info->airq.isc = VIRTIO_AIRQ_ISC;
+       rc = register_adapter_interrupt(&info->airq);
+       if (rc) {
+               airq_iv_release(info->aiv);
+               kfree(info);
+               return NULL;
+       }
+       return info;
+}
+
+static void destroy_airq_info(struct airq_info *info)
+{
+       if (!info)
+               return;
+
+       unregister_adapter_interrupt(&info->airq);
+       airq_iv_release(info->aiv);
+       kfree(info);
+}
+
+static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
+                                       u64 *first, void **airq_info)
+{
+       int i, j;
+       struct airq_info *info;
+       unsigned long indicator_addr = 0;
+       unsigned long bit, flags;
+
+       for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) {
+               if (!airq_areas[i])
+                       airq_areas[i] = new_airq_info();
+               info = airq_areas[i];
+               if (!info)
+                       return 0;
+               write_lock_irqsave(&info->lock, flags);
+               bit = airq_iv_alloc(info->aiv, nvqs);
+               if (bit == -1UL) {
+                       /* Not enough vacancies. */
+                       write_unlock_irqrestore(&info->lock, flags);
+                       continue;
+               }
+               *first = bit;
+               *airq_info = info;
+               indicator_addr = (unsigned long)info->aiv->vector;
+               for (j = 0; j < nvqs; j++) {
+                       airq_iv_set_ptr(info->aiv, bit + j,
+                                       (unsigned long)vqs[j]);
+               }
+               write_unlock_irqrestore(&info->lock, flags);
+       }
+       return indicator_addr;
+}
+
+static void virtio_ccw_drop_indicators(struct virtio_ccw_device *vcdev)
+{
+       struct virtio_ccw_vq_info *info;
+
+       list_for_each_entry(info, &vcdev->virtqueues, node)
+               drop_airq_indicator(info->vq, vcdev->airq_info);
+}
+
+static int doing_io(struct virtio_ccw_device *vcdev, __u32 flag)
+{
+       unsigned long flags;
+       __u32 ret;
+
+       spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
+       if (vcdev->err)
+               ret = 0;
+       else
+               ret = vcdev->curr_io & flag;
+       spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags);
+       return ret;
+}
+
+static int ccw_io_helper(struct virtio_ccw_device *vcdev,
+                        struct ccw1 *ccw, __u32 intparm)
+{
+       int ret;
+       unsigned long flags;
+       int flag = intparm & VIRTIO_CCW_INTPARM_MASK;
+
+       do {
+               spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags);
+               ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0);
+               if (!ret) {
+                       if (!vcdev->curr_io)
+                               vcdev->err = 0;
+                       vcdev->curr_io |= flag;
+               }
+               spin_unlock_irqrestore(get_ccwdev_lock(vcdev->cdev), flags);
+               cpu_relax();
+       } while (ret == -EBUSY);
+       wait_event(vcdev->wait_q, doing_io(vcdev, flag) == 0);
+       return ret ? ret : vcdev->err;
+}
+
+static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
+                                     struct ccw1 *ccw)
+{
+       int ret;
+       unsigned long *indicatorp = NULL;
+       struct virtio_thinint_area *thinint_area = NULL;
+       struct airq_info *airq_info = vcdev->airq_info;
+
+       if (vcdev->is_thinint) {
+               thinint_area = kzalloc(sizeof(*thinint_area),
+                                      GFP_DMA | GFP_KERNEL);
+               if (!thinint_area)
+                       return;
+               thinint_area->summary_indicator =
+                       (unsigned long) &airq_info->summary_indicator;
+               thinint_area->isc = VIRTIO_AIRQ_ISC;
+               ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
+               ccw->count = sizeof(*thinint_area);
+               ccw->cda = (__u32)(unsigned long) thinint_area;
+       } else {
+               indicatorp = kmalloc(sizeof(&vcdev->indicators),
+                                    GFP_DMA | GFP_KERNEL);
+               if (!indicatorp)
+                       return;
+               *indicatorp = 0;
+               ccw->cmd_code = CCW_CMD_SET_IND;
+               ccw->count = sizeof(vcdev->indicators);
+               ccw->cda = (__u32)(unsigned long) indicatorp;
+       }
+       /* Deregister indicators from host. */
+       vcdev->indicators = 0;
+       ccw->flags = 0;
+       ret = ccw_io_helper(vcdev, ccw,
+                           vcdev->is_thinint ?
+                           VIRTIO_CCW_DOING_SET_IND_ADAPTER :
+                           VIRTIO_CCW_DOING_SET_IND);
+       if (ret && (ret != -ENODEV))
+               dev_info(&vcdev->cdev->dev,
+                        "Failed to deregister indicators (%d)\n", ret);
+       else if (vcdev->is_thinint)
+               virtio_ccw_drop_indicators(vcdev);
+       kfree(indicatorp);
+       kfree(thinint_area);
+}
+
+static inline long do_kvm_notify(struct subchannel_id schid,
+                                unsigned long queue_index,
+                                long cookie)
+{
+       register unsigned long __nr asm("1") = KVM_S390_VIRTIO_CCW_NOTIFY;
+       register struct subchannel_id __schid asm("2") = schid;
+       register unsigned long __index asm("3") = queue_index;
+       register long __rc asm("2");
+       register long __cookie asm("4") = cookie;
+
+       asm volatile ("diag 2,4,0x500\n"
+                     : "=d" (__rc) : "d" (__nr), "d" (__schid), "d" (__index),
+                     "d"(__cookie)
+                     : "memory", "cc");
+       return __rc;
+}
+
+static bool virtio_ccw_kvm_notify(struct virtqueue *vq)
+{
+       struct virtio_ccw_vq_info *info = vq->priv;
+       struct virtio_ccw_device *vcdev;
+       struct subchannel_id schid;
+
+       vcdev = to_vc_device(info->vq->vdev);
+       ccw_device_get_schid(vcdev->cdev, &schid);
+       info->cookie = do_kvm_notify(schid, vq->index, info->cookie);
+       if (info->cookie < 0)
+               return false;
+       return true;
+}
+
+static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
+                                  struct ccw1 *ccw, int index)
+{
+       vcdev->config_block->index = index;
+       ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
+       ccw->flags = 0;
+       ccw->count = sizeof(struct vq_config_block);
+       ccw->cda = (__u32)(unsigned long)(vcdev->config_block);
+       ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
+       return vcdev->config_block->num;
+}
+
+static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vq->vdev);
+       struct virtio_ccw_vq_info *info = vq->priv;
+       unsigned long flags;
+       unsigned long size;
+       int ret;
+       unsigned int index = vq->index;
+
+       /* Remove from our list. */
+       spin_lock_irqsave(&vcdev->lock, flags);
+       list_del(&info->node);
+       spin_unlock_irqrestore(&vcdev->lock, flags);
+
+       /* Release from host. */
+       if (vcdev->revision == 0) {
+               info->info_block->l.queue = 0;
+               info->info_block->l.align = 0;
+               info->info_block->l.index = index;
+               info->info_block->l.num = 0;
+               ccw->count = sizeof(info->info_block->l);
+       } else {
+               info->info_block->s.desc = 0;
+               info->info_block->s.index = index;
+               info->info_block->s.num = 0;
+               info->info_block->s.avail = 0;
+               info->info_block->s.used = 0;
+               ccw->count = sizeof(info->info_block->s);
+       }
+       ccw->cmd_code = CCW_CMD_SET_VQ;
+       ccw->flags = 0;
+       ccw->cda = (__u32)(unsigned long)(info->info_block);
+       ret = ccw_io_helper(vcdev, ccw,
+                           VIRTIO_CCW_DOING_SET_VQ | index);
+       /*
+        * -ENODEV isn't considered an error: The device is gone anyway.
+        * This may happen on device detach.
+        */
+       if (ret && (ret != -ENODEV))
+               dev_warn(&vq->vdev->dev, "Error %d while deleting queue %d",
+                        ret, index);
+
+       vring_del_virtqueue(vq);
+       size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
+       free_pages_exact(info->queue, size);
+       kfree(info->info_block);
+       kfree(info);
+}
+
+static void virtio_ccw_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+       struct ccw1 *ccw;
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return;
+
+       virtio_ccw_drop_indicator(vcdev, ccw);
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+               virtio_ccw_del_vq(vq, ccw);
+
+       kfree(ccw);
+}
+
+static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
+                                            int i, vq_callback_t *callback,
+                                            const char *name,
+                                            struct ccw1 *ccw)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       int err;
+       struct virtqueue *vq = NULL;
+       struct virtio_ccw_vq_info *info;
+       unsigned long size = 0; /* silence the compiler */
+       unsigned long flags;
+
+       /* Allocate queue. */
+       info = kzalloc(sizeof(struct virtio_ccw_vq_info), GFP_KERNEL);
+       if (!info) {
+               dev_warn(&vcdev->cdev->dev, "no info\n");
+               err = -ENOMEM;
+               goto out_err;
+       }
+       info->info_block = kzalloc(sizeof(*info->info_block),
+                                  GFP_DMA | GFP_KERNEL);
+       if (!info->info_block) {
+               dev_warn(&vcdev->cdev->dev, "no info block\n");
+               err = -ENOMEM;
+               goto out_err;
+       }
+       info->num = virtio_ccw_read_vq_conf(vcdev, ccw, i);
+       size = PAGE_ALIGN(vring_size(info->num, KVM_VIRTIO_CCW_RING_ALIGN));
+       info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+       if (info->queue == NULL) {
+               dev_warn(&vcdev->cdev->dev, "no queue\n");
+               err = -ENOMEM;
+               goto out_err;
+       }
+
+       vq = vring_new_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, vdev,
+                                true, info->queue, virtio_ccw_kvm_notify,
+                                callback, name);
+       if (!vq) {
+               /* For now, we fail if we can't get the requested size. */
+               dev_warn(&vcdev->cdev->dev, "no vq\n");
+               err = -ENOMEM;
+               goto out_err;
+       }
+
+       /* Register it with the host. */
+       if (vcdev->revision == 0) {
+               info->info_block->l.queue = (__u64)info->queue;
+               info->info_block->l.align = KVM_VIRTIO_CCW_RING_ALIGN;
+               info->info_block->l.index = i;
+               info->info_block->l.num = info->num;
+               ccw->count = sizeof(info->info_block->l);
+       } else {
+               info->info_block->s.desc = (__u64)info->queue;
+               info->info_block->s.index = i;
+               info->info_block->s.num = info->num;
+               info->info_block->s.avail = (__u64)virtqueue_get_avail(vq);
+               info->info_block->s.used = (__u64)virtqueue_get_used(vq);
+               ccw->count = sizeof(info->info_block->s);
+       }
+       ccw->cmd_code = CCW_CMD_SET_VQ;
+       ccw->flags = 0;
+       ccw->cda = (__u32)(unsigned long)(info->info_block);
+       err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
+       if (err) {
+               dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
+               goto out_err;
+       }
+
+       info->vq = vq;
+       vq->priv = info;
+
+       /* Save it to our list. */
+       spin_lock_irqsave(&vcdev->lock, flags);
+       list_add(&info->node, &vcdev->virtqueues);
+       spin_unlock_irqrestore(&vcdev->lock, flags);
+
+       return vq;
+
+out_err:
+       if (vq)
+               vring_del_virtqueue(vq);
+       if (info) {
+               if (info->queue)
+                       free_pages_exact(info->queue, size);
+               kfree(info->info_block);
+       }
+       kfree(info);
+       return ERR_PTR(err);
+}
+
+static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
+                                          struct virtqueue *vqs[], int nvqs,
+                                          struct ccw1 *ccw)
+{
+       int ret;
+       struct virtio_thinint_area *thinint_area = NULL;
+       struct airq_info *info;
+
+       thinint_area = kzalloc(sizeof(*thinint_area), GFP_DMA | GFP_KERNEL);
+       if (!thinint_area) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       /* Try to get an indicator. */
+       thinint_area->indicator = get_airq_indicator(vqs, nvqs,
+                                                    &thinint_area->bit_nr,
+                                                    &vcdev->airq_info);
+       if (!thinint_area->indicator) {
+               ret = -ENOSPC;
+               goto out;
+       }
+       info = vcdev->airq_info;
+       thinint_area->summary_indicator =
+               (unsigned long) &info->summary_indicator;
+       thinint_area->isc = VIRTIO_AIRQ_ISC;
+       ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
+       ccw->flags = CCW_FLAG_SLI;
+       ccw->count = sizeof(*thinint_area);
+       ccw->cda = (__u32)(unsigned long)thinint_area;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
+       if (ret) {
+               if (ret == -EOPNOTSUPP) {
+                       /*
+                        * The host does not support adapter interrupts
+                        * for virtio-ccw, stop trying.
+                        */
+                       virtio_ccw_use_airq = 0;
+                       pr_info("Adapter interrupts unsupported on host\n");
+               } else
+                       dev_warn(&vcdev->cdev->dev,
+                                "enabling adapter interrupts = %d\n", ret);
+               virtio_ccw_drop_indicators(vcdev);
+       }
+out:
+       kfree(thinint_area);
+       return ret;
+}
+
+static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                              struct virtqueue *vqs[],
+                              vq_callback_t *callbacks[],
+                              const char *names[])
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       unsigned long *indicatorp = NULL;
+       int ret, i;
+       struct ccw1 *ccw;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return -ENOMEM;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i],
+                                            ccw);
+               if (IS_ERR(vqs[i])) {
+                       ret = PTR_ERR(vqs[i]);
+                       vqs[i] = NULL;
+                       goto out;
+               }
+       }
+       ret = -ENOMEM;
+       /* We need a data area under 2G to communicate. */
+       indicatorp = kmalloc(sizeof(&vcdev->indicators), GFP_DMA | GFP_KERNEL);
+       if (!indicatorp)
+               goto out;
+       *indicatorp = (unsigned long) &vcdev->indicators;
+       if (vcdev->is_thinint) {
+               ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
+               if (ret)
+                       /* no error, just fall back to legacy interrupts */
+                       vcdev->is_thinint = 0;
+       }
+       if (!vcdev->is_thinint) {
+               /* Register queue indicators with host. */
+               vcdev->indicators = 0;
+               ccw->cmd_code = CCW_CMD_SET_IND;
+               ccw->flags = 0;
+               ccw->count = sizeof(vcdev->indicators);
+               ccw->cda = (__u32)(unsigned long) indicatorp;
+               ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
+               if (ret)
+                       goto out;
+       }
+       /* Register indicators2 with host for config changes */
+       *indicatorp = (unsigned long) &vcdev->indicators2;
+       vcdev->indicators2 = 0;
+       ccw->cmd_code = CCW_CMD_SET_CONF_IND;
+       ccw->flags = 0;
+       ccw->count = sizeof(vcdev->indicators2);
+       ccw->cda = (__u32)(unsigned long) indicatorp;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
+       if (ret)
+               goto out;
+
+       kfree(indicatorp);
+       kfree(ccw);
+       return 0;
+out:
+       kfree(indicatorp);
+       kfree(ccw);
+       virtio_ccw_del_vqs(vdev);
+       return ret;
+}
+
+static void virtio_ccw_reset(struct virtio_device *vdev)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       struct ccw1 *ccw;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return;
+
+       /* Zero status bits. */
+       *vcdev->status = 0;
+
+       /* Send a reset ccw on device. */
+       ccw->cmd_code = CCW_CMD_VDEV_RESET;
+       ccw->flags = 0;
+       ccw->count = 0;
+       ccw->cda = 0;
+       ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_RESET);
+       kfree(ccw);
+}
+
+static u64 virtio_ccw_get_features(struct virtio_device *vdev)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       struct virtio_feature_desc *features;
+       int ret;
+       u64 rc;
+       struct ccw1 *ccw;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return 0;
+
+       features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
+       if (!features) {
+               rc = 0;
+               goto out_free;
+       }
+       /* Read the feature bits from the host. */
+       features->index = 0;
+       ccw->cmd_code = CCW_CMD_READ_FEAT;
+       ccw->flags = 0;
+       ccw->count = sizeof(*features);
+       ccw->cda = (__u32)(unsigned long)features;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
+       if (ret) {
+               rc = 0;
+               goto out_free;
+       }
+
+       rc = le32_to_cpu(features->features);
+
+       if (vcdev->revision == 0)
+               goto out_free;
+
+       /* Read second half of the feature bits from the host. */
+       features->index = 1;
+       ccw->cmd_code = CCW_CMD_READ_FEAT;
+       ccw->flags = 0;
+       ccw->count = sizeof(*features);
+       ccw->cda = (__u32)(unsigned long)features;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
+       if (ret == 0)
+               rc |= (u64)le32_to_cpu(features->features) << 32;
+
+out_free:
+       kfree(features);
+       kfree(ccw);
+       return rc;
+}
+
+static int virtio_ccw_finalize_features(struct virtio_device *vdev)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       struct virtio_feature_desc *features;
+       struct ccw1 *ccw;
+       int ret;
+
+       if (vcdev->revision >= 1 &&
+           !__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
+               dev_err(&vdev->dev, "virtio: device uses revision 1 "
+                       "but does not have VIRTIO_F_VERSION_1\n");
+               return -EINVAL;
+       }
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return -ENOMEM;
+
+       features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
+       if (!features) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       /* Give virtio_ring a chance to accept features. */
+       vring_transport_features(vdev);
+
+       features->index = 0;
+       features->features = cpu_to_le32((u32)vdev->features);
+       /* Write the first half of the feature bits to the host. */
+       ccw->cmd_code = CCW_CMD_WRITE_FEAT;
+       ccw->flags = 0;
+       ccw->count = sizeof(*features);
+       ccw->cda = (__u32)(unsigned long)features;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
+       if (ret)
+               goto out_free;
+
+       if (vcdev->revision == 0)
+               goto out_free;
+
+       features->index = 1;
+       features->features = cpu_to_le32(vdev->features >> 32);
+       /* Write the second half of the feature bits to the host. */
+       ccw->cmd_code = CCW_CMD_WRITE_FEAT;
+       ccw->flags = 0;
+       ccw->count = sizeof(*features);
+       ccw->cda = (__u32)(unsigned long)features;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
+
+out_free:
+       kfree(features);
+       kfree(ccw);
+
+       return ret;
+}
+
+static void virtio_ccw_get_config(struct virtio_device *vdev,
+                                 unsigned int offset, void *buf, unsigned len)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       int ret;
+       struct ccw1 *ccw;
+       void *config_area;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return;
+
+       config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
+       if (!config_area)
+               goto out_free;
+
+       /* Read the config area from the host. */
+       ccw->cmd_code = CCW_CMD_READ_CONF;
+       ccw->flags = 0;
+       ccw->count = offset + len;
+       ccw->cda = (__u32)(unsigned long)config_area;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG);
+       if (ret)
+               goto out_free;
+
+       memcpy(vcdev->config, config_area, offset + len);
+       if (buf)
+               memcpy(buf, &vcdev->config[offset], len);
+       if (vcdev->config_ready < offset + len)
+               vcdev->config_ready = offset + len;
+
+out_free:
+       kfree(config_area);
+       kfree(ccw);
+}
+
+static void virtio_ccw_set_config(struct virtio_device *vdev,
+                                 unsigned int offset, const void *buf,
+                                 unsigned len)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       struct ccw1 *ccw;
+       void *config_area;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return;
+
+       config_area = kzalloc(VIRTIO_CCW_CONFIG_SIZE, GFP_DMA | GFP_KERNEL);
+       if (!config_area)
+               goto out_free;
+
+       /* Make sure we don't overwrite fields. */
+       if (vcdev->config_ready < offset)
+               virtio_ccw_get_config(vdev, 0, NULL, offset);
+       memcpy(&vcdev->config[offset], buf, len);
+       /* Write the config area to the host. */
+       memcpy(config_area, vcdev->config, sizeof(vcdev->config));
+       ccw->cmd_code = CCW_CMD_WRITE_CONF;
+       ccw->flags = 0;
+       ccw->count = offset + len;
+       ccw->cda = (__u32)(unsigned long)config_area;
+       ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
+
+out_free:
+       kfree(config_area);
+       kfree(ccw);
+}
+
+static u8 virtio_ccw_get_status(struct virtio_device *vdev)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+
+       return *vcdev->status;
+}
+
+static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
+{
+       struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+       u8 old_status = *vcdev->status;
+       struct ccw1 *ccw;
+       int ret;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return;
+
+       /* Write the status to the host. */
+       *vcdev->status = status;
+       ccw->cmd_code = CCW_CMD_WRITE_STATUS;
+       ccw->flags = 0;
+       ccw->count = sizeof(status);
+       ccw->cda = (__u32)(unsigned long)vcdev->status;
+       ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
+       /* Write failed? We assume status is unchanged. */
+       if (ret)
+               *vcdev->status = old_status;
+       kfree(ccw);
+}
+
+static struct virtio_config_ops virtio_ccw_config_ops = {
+       .get_features = virtio_ccw_get_features,
+       .finalize_features = virtio_ccw_finalize_features,
+       .get = virtio_ccw_get_config,
+       .set = virtio_ccw_set_config,
+       .get_status = virtio_ccw_get_status,
+       .set_status = virtio_ccw_set_status,
+       .reset = virtio_ccw_reset,
+       .find_vqs = virtio_ccw_find_vqs,
+       .del_vqs = virtio_ccw_del_vqs,
+};
+
+
+/*
+ * ccw bus driver related functions
+ */
+
+static void virtio_ccw_release_dev(struct device *_d)
+{
+       struct virtio_device *dev = container_of(_d, struct virtio_device,
+                                                dev);
+       struct virtio_ccw_device *vcdev = to_vc_device(dev);
+
+       kfree(vcdev->status);
+       kfree(vcdev->config_block);
+       kfree(vcdev);
+}
+
+static int irb_is_error(struct irb *irb)
+{
+       if (scsw_cstat(&irb->scsw) != 0)
+               return 1;
+       if (scsw_dstat(&irb->scsw) & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+               return 1;
+       if (scsw_cc(&irb->scsw) != 0)
+               return 1;
+       return 0;
+}
+
+static struct virtqueue *virtio_ccw_vq_by_ind(struct virtio_ccw_device *vcdev,
+                                             int index)
+{
+       struct virtio_ccw_vq_info *info;
+       unsigned long flags;
+       struct virtqueue *vq;
+
+       vq = NULL;
+       spin_lock_irqsave(&vcdev->lock, flags);
+       list_for_each_entry(info, &vcdev->virtqueues, node) {
+               if (info->vq->index == index) {
+                       vq = info->vq;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&vcdev->lock, flags);
+       return vq;
+}
+
+static void virtio_ccw_int_handler(struct ccw_device *cdev,
+                                  unsigned long intparm,
+                                  struct irb *irb)
+{
+       __u32 activity = intparm & VIRTIO_CCW_INTPARM_MASK;
+       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+       int i;
+       struct virtqueue *vq;
+
+       if (!vcdev)
+               return;
+       /* Check if it's a notification from the host. */
+       if ((intparm == 0) &&
+           (scsw_stctl(&irb->scsw) ==
+            (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) {
+               /* OK */
+       }
+       if (irb_is_error(irb)) {
+               /* Command reject? */
+               if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
+                   (irb->ecw[0] & SNS0_CMD_REJECT))
+                       vcdev->err = -EOPNOTSUPP;
+               else
+                       /* Map everything else to -EIO. */
+                       vcdev->err = -EIO;
+       }
+       if (vcdev->curr_io & activity) {
+               switch (activity) {
+               case VIRTIO_CCW_DOING_READ_FEAT:
+               case VIRTIO_CCW_DOING_WRITE_FEAT:
+               case VIRTIO_CCW_DOING_READ_CONFIG:
+               case VIRTIO_CCW_DOING_WRITE_CONFIG:
+               case VIRTIO_CCW_DOING_WRITE_STATUS:
+               case VIRTIO_CCW_DOING_SET_VQ:
+               case VIRTIO_CCW_DOING_SET_IND:
+               case VIRTIO_CCW_DOING_SET_CONF_IND:
+               case VIRTIO_CCW_DOING_RESET:
+               case VIRTIO_CCW_DOING_READ_VQ_CONF:
+               case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
+               case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
+                       vcdev->curr_io &= ~activity;
+                       wake_up(&vcdev->wait_q);
+                       break;
+               default:
+                       /* don't know what to do... */
+                       dev_warn(&cdev->dev, "Suspicious activity '%08x'\n",
+                                activity);
+                       WARN_ON(1);
+                       break;
+               }
+       }
+       for_each_set_bit(i, &vcdev->indicators,
+                        sizeof(vcdev->indicators) * BITS_PER_BYTE) {
+               /* The bit clear must happen before the vring kick. */
+               clear_bit(i, &vcdev->indicators);
+               barrier();
+               vq = virtio_ccw_vq_by_ind(vcdev, i);
+               vring_interrupt(0, vq);
+       }
+       if (test_bit(0, &vcdev->indicators2)) {
+               virtio_config_changed(&vcdev->vdev);
+               clear_bit(0, &vcdev->indicators2);
+       }
+}
+
+/*
+ * We usually want to autoonline all devices, but give the admin
+ * a way to exempt devices from this.
+ */
+#define __DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
+                    (8*sizeof(long)))
+static unsigned long devs_no_auto[__MAX_SSID + 1][__DEV_WORDS];
+
+static char *no_auto = "";
+
+module_param(no_auto, charp, 0444);
+MODULE_PARM_DESC(no_auto, "list of ccw bus id ranges not to be auto-onlined");
+
+static int virtio_ccw_check_autoonline(struct ccw_device *cdev)
+{
+       struct ccw_dev_id id;
+
+       ccw_device_get_id(cdev, &id);
+       if (test_bit(id.devno, devs_no_auto[id.ssid]))
+               return 0;
+       return 1;
+}
+
+static void virtio_ccw_auto_online(void *data, async_cookie_t cookie)
+{
+       struct ccw_device *cdev = data;
+       int ret;
+
+       ret = ccw_device_set_online(cdev);
+       if (ret)
+               dev_warn(&cdev->dev, "Failed to set online: %d\n", ret);
+}
+
+static int virtio_ccw_probe(struct ccw_device *cdev)
+{
+       cdev->handler = virtio_ccw_int_handler;
+
+       if (virtio_ccw_check_autoonline(cdev))
+               async_schedule(virtio_ccw_auto_online, cdev);
+       return 0;
+}
+
+static struct virtio_ccw_device *virtio_grab_drvdata(struct ccw_device *cdev)
+{
+       unsigned long flags;
+       struct virtio_ccw_device *vcdev;
+
+       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+       vcdev = dev_get_drvdata(&cdev->dev);
+       if (!vcdev || vcdev->going_away) {
+               spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+               return NULL;
+       }
+       vcdev->going_away = true;
+       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+       return vcdev;
+}
+
+static void virtio_ccw_remove(struct ccw_device *cdev)
+{
+       unsigned long flags;
+       struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
+
+       if (vcdev && cdev->online) {
+               if (vcdev->device_lost)
+                       virtio_break_device(&vcdev->vdev);
+               unregister_virtio_device(&vcdev->vdev);
+               spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+               dev_set_drvdata(&cdev->dev, NULL);
+               spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+       }
+       cdev->handler = NULL;
+}
+
+static int virtio_ccw_offline(struct ccw_device *cdev)
+{
+       unsigned long flags;
+       struct virtio_ccw_device *vcdev = virtio_grab_drvdata(cdev);
+
+       if (!vcdev)
+               return 0;
+       if (vcdev->device_lost)
+               virtio_break_device(&vcdev->vdev);
+       unregister_virtio_device(&vcdev->vdev);
+       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+       dev_set_drvdata(&cdev->dev, NULL);
+       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+       return 0;
+}
+
+static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
+{
+       struct virtio_rev_info *rev;
+       struct ccw1 *ccw;
+       int ret;
+
+       ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+       if (!ccw)
+               return -ENOMEM;
+       rev = kzalloc(sizeof(*rev), GFP_DMA | GFP_KERNEL);
+       if (!rev) {
+               kfree(ccw);
+               return -ENOMEM;
+       }
+
+       /* Set transport revision */
+       ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV;
+       ccw->flags = 0;
+       ccw->count = sizeof(*rev);
+       ccw->cda = (__u32)(unsigned long)rev;
+
+       vcdev->revision = VIRTIO_CCW_REV_MAX;
+       do {
+               rev->revision = vcdev->revision;
+               /* none of our supported revisions carry payload */
+               rev->length = 0;
+               ret = ccw_io_helper(vcdev, ccw,
+                                   VIRTIO_CCW_DOING_SET_VIRTIO_REV);
+               if (ret == -EOPNOTSUPP) {
+                       if (vcdev->revision == 0)
+                               /*
+                                * The host device does not support setting
+                                * the revision: let's operate it in legacy
+                                * mode.
+                                */
+                               ret = 0;
+                       else
+                               vcdev->revision--;
+               }
+       } while (ret == -EOPNOTSUPP);
+
+       kfree(ccw);
+       kfree(rev);
+       return ret;
+}
+
+static int virtio_ccw_online(struct ccw_device *cdev)
+{
+       int ret;
+       struct virtio_ccw_device *vcdev;
+       unsigned long flags;
+
+       vcdev = kzalloc(sizeof(*vcdev), GFP_KERNEL);
+       if (!vcdev) {
+               dev_warn(&cdev->dev, "Could not get memory for virtio\n");
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       vcdev->config_block = kzalloc(sizeof(*vcdev->config_block),
+                                  GFP_DMA | GFP_KERNEL);
+       if (!vcdev->config_block) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+       vcdev->status = kzalloc(sizeof(*vcdev->status), GFP_DMA | GFP_KERNEL);
+       if (!vcdev->status) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       vcdev->is_thinint = virtio_ccw_use_airq; /* at least try */
+
+       vcdev->vdev.dev.parent = &cdev->dev;
+       vcdev->vdev.dev.release = virtio_ccw_release_dev;
+       vcdev->vdev.config = &virtio_ccw_config_ops;
+       vcdev->cdev = cdev;
+       init_waitqueue_head(&vcdev->wait_q);
+       INIT_LIST_HEAD(&vcdev->virtqueues);
+       spin_lock_init(&vcdev->lock);
+
+       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+       dev_set_drvdata(&cdev->dev, vcdev);
+       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+       vcdev->vdev.id.vendor = cdev->id.cu_type;
+       vcdev->vdev.id.device = cdev->id.cu_model;
+
+       ret = virtio_ccw_set_transport_rev(vcdev);
+       if (ret)
+               goto out_free;
+
+       ret = register_virtio_device(&vcdev->vdev);
+       if (ret) {
+               dev_warn(&cdev->dev, "Failed to register virtio device: %d\n",
+                        ret);
+               goto out_put;
+       }
+       return 0;
+out_put:
+       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+       dev_set_drvdata(&cdev->dev, NULL);
+       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+       put_device(&vcdev->vdev.dev);
+       return ret;
+out_free:
+       if (vcdev) {
+               kfree(vcdev->status);
+               kfree(vcdev->config_block);
+       }
+       kfree(vcdev);
+       return ret;
+}
+
+static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event)
+{
+       int rc;
+       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+
+       /*
+        * Make sure vcdev is set
+        * i.e. set_offline/remove callback not already running
+        */
+       if (!vcdev)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case CIO_GONE:
+               vcdev->device_lost = true;
+               rc = NOTIFY_DONE;
+               break;
+       default:
+               rc = NOTIFY_DONE;
+               break;
+       }
+       return rc;
+}
+
+static struct ccw_device_id virtio_ids[] = {
+       { CCW_DEVICE(0x3832, 0) },
+       {},
+};
+MODULE_DEVICE_TABLE(ccw, virtio_ids);
+
+static struct ccw_driver virtio_ccw_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "virtio_ccw",
+       },
+       .ids = virtio_ids,
+       .probe = virtio_ccw_probe,
+       .remove = virtio_ccw_remove,
+       .set_offline = virtio_ccw_offline,
+       .set_online = virtio_ccw_online,
+       .notify = virtio_ccw_cio_notify,
+       .int_class = IRQIO_VIR,
+};
+
+static int __init pure_hex(char **cp, unsigned int *val, int min_digit,
+                          int max_digit, int max_val)
+{
+       int diff;
+
+       diff = 0;
+       *val = 0;
+
+       while (diff <= max_digit) {
+               int value = hex_to_bin(**cp);
+
+               if (value < 0)
+                       break;
+               *val = *val * 16 + value;
+               (*cp)++;
+               diff++;
+       }
+
+       if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
+               return 1;
+
+       return 0;
+}
+
+static int __init parse_busid(char *str, unsigned int *cssid,
+                             unsigned int *ssid, unsigned int *devno)
+{
+       char *str_work;
+       int rc, ret;
+
+       rc = 1;
+
+       if (*str == '\0')
+               goto out;
+
+       str_work = str;
+       ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
+       if (ret || (str_work[0] != '.'))
+               goto out;
+       str_work++;
+       ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
+       if (ret || (str_work[0] != '.'))
+               goto out;
+       str_work++;
+       ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
+       if (ret || (str_work[0] != '\0'))
+               goto out;
+
+       rc = 0;
+out:
+       return rc;
+}
+
+static void __init no_auto_parse(void)
+{
+       unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
+       char *parm, *str;
+       int rc;
+
+       str = no_auto;
+       while ((parm = strsep(&str, ","))) {
+               rc = parse_busid(strsep(&parm, "-"), &from_cssid,
+                                &from_ssid, &from);
+               if (rc)
+                       continue;
+               if (parm != NULL) {
+                       rc = parse_busid(parm, &to_cssid,
+                                        &to_ssid, &to);
+                       if ((from_ssid > to_ssid) ||
+                           ((from_ssid == to_ssid) && (from > to)))
+                               rc = -EINVAL;
+               } else {
+                       to_cssid = from_cssid;
+                       to_ssid = from_ssid;
+                       to = from;
+               }
+               if (rc)
+                       continue;
+               while ((from_ssid < to_ssid) ||
+                      ((from_ssid == to_ssid) && (from <= to))) {
+                       set_bit(from, devs_no_auto[from_ssid]);
+                       from++;
+                       if (from > __MAX_SUBCHANNEL) {
+                               from_ssid++;
+                               from = 0;
+                       }
+               }
+       }
+}
+
+static int __init virtio_ccw_init(void)
+{
+       /* parse no_auto string before we do anything further */
+       no_auto_parse();
+       return ccw_driver_register(&virtio_ccw_driver);
+}
+module_init(virtio_ccw_init);
+
+static void __exit virtio_ccw_exit(void)
+{
+       int i;
+
+       ccw_driver_unregister(&virtio_ccw_driver);
+       for (i = 0; i < MAX_AIRQ_AREAS; i++)
+               destroy_airq_info(airq_areas[i]);
+}
+module_exit(virtio_ccw_exit);
index 26270c351624f229cf85b6069ffe53ee26d50bef..ce129e595b55b663a11600e46571a1dba0d2ccf7 100644 (file)
@@ -39,7 +39,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.6.0.17"
+#define DRV_VERSION            "1.6.0.17a"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
index 155b286f1a9d3cc8b366a6a5b7610ae562337f62..25436cd2860cc18a63ac599ed58e3c871c264d8e 100644 (file)
@@ -425,6 +425,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
        unsigned long ptr;
        struct fc_rport_priv *rdata;
        spinlock_t *io_lock = NULL;
+       int io_lock_acquired = 0;
 
        if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -518,6 +519,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
        spin_lock_irqsave(io_lock, flags);
 
        /* initialize rest of io_req */
+       io_lock_acquired = 1;
        io_req->port_id = rport->port_id;
        io_req->start_time = jiffies;
        CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING;
@@ -571,7 +573,7 @@ out:
                  (((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc)));
 
        /* if only we issued IO, will we have the io lock */
-       if (CMD_FLAGS(sc) & FNIC_IO_INITIALIZED)
+       if (io_lock_acquired)
                spin_unlock_irqrestore(io_lock, flags);
 
        atomic_dec(&fnic->in_flight);
index 882744852aacb822aa3264bf75fe761b2d494c9f..a9aa38903efefeeccf1dff34ad201af7283d70d9 100644 (file)
@@ -599,9 +599,10 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
 {
        struct ipr_trace_entry *trace_entry;
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       unsigned int trace_index;
 
-       trace_entry = &ioa_cfg->trace[atomic_add_return
-                       (1, &ioa_cfg->trace_index)%IPR_NUM_TRACE_ENTRIES];
+       trace_index = atomic_add_return(1, &ioa_cfg->trace_index) & IPR_TRACE_INDEX_MASK;
+       trace_entry = &ioa_cfg->trace[trace_index];
        trace_entry->time = jiffies;
        trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
        trace_entry->type = type;
@@ -1051,10 +1052,15 @@ static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd,
 
 static int ipr_get_hrrq_index(struct ipr_ioa_cfg *ioa_cfg)
 {
+       unsigned int hrrq;
+
        if (ioa_cfg->hrrq_num == 1)
-               return 0;
-       else
-               return (atomic_add_return(1, &ioa_cfg->hrrq_index) % (ioa_cfg->hrrq_num - 1)) + 1;
+               hrrq = 0;
+       else {
+               hrrq = atomic_add_return(1, &ioa_cfg->hrrq_index);
+               hrrq = (hrrq % (ioa_cfg->hrrq_num - 1)) + 1;
+       }
+       return hrrq;
 }
 
 /**
@@ -6263,21 +6269,23 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
-       unsigned long hrrq_flags;
+       unsigned long lock_flags;
 
        scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len));
 
        if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
                scsi_dma_unmap(scsi_cmd);
 
-               spin_lock_irqsave(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags);
                list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
                scsi_cmd->scsi_done(scsi_cmd);
-               spin_unlock_irqrestore(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags);
        } else {
-               spin_lock_irqsave(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+               spin_lock(&ipr_cmd->hrrq->_lock);
                ipr_erp_start(ioa_cfg, ipr_cmd);
-               spin_unlock_irqrestore(ipr_cmd->hrrq->lock, hrrq_flags);
+               spin_unlock(&ipr_cmd->hrrq->_lock);
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        }
 }
 
index 73790a1d096902fbda79f39ca7bd5c1bd43a1119..6b97ee45c7b460d0719f99baa011a6e13706aa67 100644 (file)
@@ -1486,6 +1486,7 @@ struct ipr_ioa_cfg {
 
 #define IPR_NUM_TRACE_INDEX_BITS       8
 #define IPR_NUM_TRACE_ENTRIES          (1 << IPR_NUM_TRACE_INDEX_BITS)
+#define IPR_TRACE_INDEX_MASK           (IPR_NUM_TRACE_ENTRIES - 1)
 #define IPR_TRACE_SIZE (sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES)
        char trace_start[8];
 #define IPR_TRACE_START_LABEL                  "trace"
index 1b3a094734522803c7f3fecd39da5c297a1feb43..30f9ef0c0d4f8cea52b182f370a04ed1ba4a9908 100644 (file)
@@ -733,8 +733,6 @@ static bool fc_invoke_resp(struct fc_exch *ep, struct fc_seq *sp,
        if (resp) {
                resp(sp, fp, arg);
                res = true;
-       } else if (!IS_ERR(fp)) {
-               fc_frame_free(fp);
        }
 
        spin_lock_bh(&ep->ex_lock);
@@ -1596,7 +1594,8 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
         * If new exch resp handler is valid then call that
         * first.
         */
-       fc_invoke_resp(ep, sp, fp);
+       if (!fc_invoke_resp(ep, sp, fp))
+               fc_frame_free(fp);
 
        fc_exch_release(ep);
        return;
@@ -1695,7 +1694,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
        fc_exch_hold(ep);
        if (!rc)
                fc_exch_delete(ep);
-       fc_invoke_resp(ep, sp, fp);
+       if (!fc_invoke_resp(ep, sp, fp))
+               fc_frame_free(fp);
        if (has_rec)
                fc_exch_timer_set(ep, ep->r_a_tov);
        fc_exch_release(ep);
index c6795941b45d98579cd6117cc5b72f8c5c4d0bf9..2d5909c4685ca63375f5041d960effada171f5fc 100644 (file)
@@ -1039,11 +1039,26 @@ restart:
                fc_fcp_pkt_hold(fsp);
                spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
 
-               if (!fc_fcp_lock_pkt(fsp)) {
+               spin_lock_bh(&fsp->scsi_pkt_lock);
+               if (!(fsp->state & FC_SRB_COMPL)) {
+                       fsp->state |= FC_SRB_COMPL;
+                       /*
+                        * TODO: dropping scsi_pkt_lock and then reacquiring
+                        * again around fc_fcp_cleanup_cmd() is required,
+                        * since fc_fcp_cleanup_cmd() calls into
+                        * fc_seq_set_resp() and that func preempts cpu using
+                        * schedule. May be schedule and related code should be
+                        * removed instead of unlocking here to avoid scheduling
+                        * while atomic bug.
+                        */
+                       spin_unlock_bh(&fsp->scsi_pkt_lock);
+
                        fc_fcp_cleanup_cmd(fsp, error);
+
+                       spin_lock_bh(&fsp->scsi_pkt_lock);
                        fc_io_compl(fsp);
-                       fc_fcp_unlock_pkt(fsp);
                }
+               spin_unlock_bh(&fsp->scsi_pkt_lock);
 
                fc_fcp_pkt_release(fsp);
                spin_lock_irqsave(&si->scsi_queue_lock, flags);
index 8053f24f03499335112721cd50c2816da40393a6..98d9bb6ff725ff46621a408bdf1f208175e21daf 100644 (file)
@@ -2941,10 +2941,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 {
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
-       unsigned long flags;
 
        del_timer_sync(&conn->transport_timer);
 
+       mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->frwd_lock);
        conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
        if (session->leadconn == conn) {
@@ -2956,28 +2956,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        }
        spin_unlock_bh(&session->frwd_lock);
 
-       /*
-        * Block until all in-progress commands for this connection
-        * time out or fail.
-        */
-       for (;;) {
-               spin_lock_irqsave(session->host->host_lock, flags);
-               if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */
-                       spin_unlock_irqrestore(session->host->host_lock, flags);
-                       break;
-               }
-               spin_unlock_irqrestore(session->host->host_lock, flags);
-               msleep_interruptible(500);
-               iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
-                                 "host_busy %d host_failed %d\n",
-                                 atomic_read(&session->host->host_busy),
-                                 session->host->host_failed);
-               /*
-                * force eh_abort() to unblock
-                */
-               wake_up(&conn->ehwait);
-       }
-
        /* flush queued up work because we free the connection below */
        iscsi_suspend_tx(conn);
 
@@ -2994,6 +2972,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        if (session->leadconn == conn)
                session->leadconn = NULL;
        spin_unlock_bh(&session->frwd_lock);
+       mutex_unlock(&session->eh_mutex);
 
        iscsi_destroy_conn(cls_conn);
 }
index 82b92c414a9cfe3152933e9cfc191c79c480568c..437254e1c4dee0c9972ff723ad31575911002993 100644 (file)
@@ -738,7 +738,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                ql_log(ql_log_info, vha, 0x706f,
                    "Issuing MPI reset.\n");
 
-               if (IS_QLA83XX(ha)) {
+               if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
                        uint32_t idc_control;
 
                        qla83xx_idc_lock(vha, 0);
index 0e6ee3ca30e667591db375ba73d9009b286ec93b..8b011aef12bd5ec6e72f5d7a57bfa2285ae64404 100644 (file)
  * |                              |                    | 0xd031-0xd0ff |
  * |                              |                    | 0xd101-0xd1fe |
  * |                              |                    | 0xd214-0xd2fe |
- * | Target Mode                 |       0xe079       |                |
- * | Target Mode Management      |       0xf072       | 0xf002         |
+ * | Target Mode                 |       0xe080       |                |
+ * | Target Mode Management      |       0xf096       | 0xf002         |
  * |                              |                    | 0xf046-0xf049  |
- * | Target Mode Task Management  |      0x1000b      |                |
+ * | Target Mode Task Management  |      0x1000d      |                |
  * ----------------------------------------------------------------------
  */
 
index e86201d3b8c6d9eccbd1132e96cffb08310b7988..9ad819edcd67af2c73ca5a0a85a8863398b3c6f7 100644 (file)
 #define RESPONSE_ENTRY_CNT_FX00                256     /* Number of response entries.*/
 
 struct req_que;
+struct qla_tgt_sess;
 
 /*
  * (sd.h is not exported, hence local inclusion)
@@ -2026,6 +2027,7 @@ typedef struct fc_port {
        uint16_t port_id;
 
        unsigned long retry_delay_timestamp;
+       struct qla_tgt_sess *tgt_session;
 } fc_port_t;
 
 #include "qla_mr.h"
@@ -3154,13 +3156,13 @@ struct qla_hw_data {
 /* Bit 21 of fw_attributes decides the MCTP capabilities */
 #define IS_MCTP_CAPABLE(ha)    (IS_QLA2031(ha) && \
                                ((ha)->fw_attributes_ext[0] & BIT_0))
-#define IS_PI_UNINIT_CAPABLE(ha)       (IS_QLA83XX(ha))
-#define IS_PI_IPGUARD_CAPABLE(ha)      (IS_QLA83XX(ha))
+#define IS_PI_UNINIT_CAPABLE(ha)       (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+#define IS_PI_IPGUARD_CAPABLE(ha)      (IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_PI_DIFB_DIX0_CAPABLE(ha)    (0)
-#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha)        (IS_QLA83XX(ha))
+#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha)        (IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_PI_SPLIT_DET_CAPABLE(ha)    (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \
     (((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22))
-#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha))
+#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_TGT_MODE_CAPABLE(ha)        (ha->tgt.atio_q_length)
 #define IS_SHADOW_REG_CAPABLE(ha)  (IS_QLA27XX(ha))
 #define IS_DPORT_CAPABLE(ha)  (IS_QLA83XX(ha) || IS_QLA27XX(ha))
@@ -3579,6 +3581,16 @@ typedef struct scsi_qla_host {
        uint16_t        fcoe_fcf_idx;
        uint8_t         fcoe_vn_port_mac[6];
 
+       /* list of commands waiting on workqueue */
+       struct list_head        qla_cmd_list;
+       struct list_head        qla_sess_op_cmd_list;
+       spinlock_t              cmd_list_lock;
+
+       /* Counter to detect races between ELS and RSCN events */
+       atomic_t                generation_tick;
+       /* Time when global fcport update has been scheduled */
+       int                     total_fcport_update_gen;
+
        uint32_t        vp_abort_cnt;
 
        struct fc_vport *fc_vport;      /* holds fc_vport * for each vport */
index 664013115c9da7d7912d0b22fa34ddf91e7b977b..11f2f3279eab2984fe131510cc669b329f149bae 100644 (file)
@@ -115,6 +115,8 @@ qla2x00_async_iocb_timeout(void *data)
                        QLA_LOGIO_LOGIN_RETRIED : 0;
                qla2x00_post_async_login_done_work(fcport->vha, fcport,
                        lio->u.logio.data);
+       } else if (sp->type == SRB_LOGOUT_CMD) {
+               qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT);
        }
 }
 
@@ -497,7 +499,10 @@ void
 qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
-       qla2x00_mark_device_lost(vha, fcport, 1, 0);
+       /* Don't re-login in target mode */
+       if (!fcport->tgt_session)
+               qla2x00_mark_device_lost(vha, fcport, 1, 0);
+       qlt_logo_completion_handler(fcport, data[0]);
        return;
 }
 
@@ -1538,7 +1543,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                mem_size = (ha->fw_memory_size - 0x11000 + 1) *
                    sizeof(uint16_t);
        } else if (IS_FWI2_CAPABLE(ha)) {
-               if (IS_QLA83XX(ha))
+               if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
                        fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
                else if (IS_QLA81XX(ha))
                        fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
@@ -1550,7 +1555,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                mem_size = (ha->fw_memory_size - 0x100000 + 1) *
                    sizeof(uint32_t);
                if (ha->mqenable) {
-                       if (!IS_QLA83XX(ha))
+                       if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                                mq_size = sizeof(struct qla2xxx_mq_chain);
                        /*
                         * Allocate maximum buffer size for all queues.
@@ -2922,21 +2927,14 @@ qla2x00_rport_del(void *data)
 {
        fc_port_t *fcport = data;
        struct fc_rport *rport;
-       scsi_qla_host_t *vha = fcport->vha;
        unsigned long flags;
 
        spin_lock_irqsave(fcport->vha->host->host_lock, flags);
        rport = fcport->drport ? fcport->drport: fcport->rport;
        fcport->drport = NULL;
        spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
-       if (rport) {
+       if (rport)
                fc_remote_port_delete(rport);
-               /*
-                * Release the target mode FC NEXUS in qla_target.c code
-                * if target mod is enabled.
-                */
-               qlt_fc_port_deleted(vha, fcport);
-       }
 }
 
 /**
@@ -3303,6 +3301,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
         * Create target mode FC NEXUS in qla_target.c if target mode is
         * enabled..
         */
+
        qlt_fc_port_added(vha, fcport);
 
        spin_lock_irqsave(fcport->vha->host->host_lock, flags);
@@ -3341,8 +3340,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 
        if (IS_QLAFX00(vha->hw)) {
                qla2x00_set_fcport_state(fcport, FCS_ONLINE);
-               qla2x00_reg_remote_port(vha, fcport);
-               return;
+               goto reg_port;
        }
        fcport->login_retry = 0;
        fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
@@ -3350,7 +3348,16 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
        qla2x00_set_fcport_state(fcport, FCS_ONLINE);
        qla2x00_iidma_fcport(vha, fcport);
        qla24xx_update_fcport_fcp_prio(vha, fcport);
-       qla2x00_reg_remote_port(vha, fcport);
+
+reg_port:
+       if (qla_ini_mode_enabled(vha))
+               qla2x00_reg_remote_port(vha, fcport);
+       else {
+               /*
+                * Create target mode FC NEXUS in qla_target.c
+                */
+               qlt_fc_port_added(vha, fcport);
+       }
 }
 
 /*
@@ -3375,6 +3382,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
        LIST_HEAD(new_fcports);
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+       int             discovery_gen;
 
        /* If FL port exists, then SNS is present */
        if (IS_FWI2_CAPABLE(ha))
@@ -3445,6 +3453,14 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                        fcport->scan_state = QLA_FCPORT_SCAN;
                }
 
+               /* Mark the time right before querying FW for connected ports.
+                * This process is long, asynchronous and by the time it's done,
+                * collected information might not be accurate anymore. E.g.
+                * disconnected port might have re-connected and a brand new
+                * session has been created. In this case session's generation
+                * will be newer than discovery_gen. */
+               qlt_do_generation_tick(vha, &discovery_gen);
+
                rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
                if (rval != QLA_SUCCESS)
                        break;
@@ -3460,20 +3476,44 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                        if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
                                continue;
 
-                       if (fcport->scan_state == QLA_FCPORT_SCAN &&
-                           atomic_read(&fcport->state) == FCS_ONLINE) {
-                               qla2x00_mark_device_lost(vha, fcport,
-                                   ql2xplogiabsentdevice, 0);
-                               if (fcport->loop_id != FC_NO_LOOP_ID &&
-                                   (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
-                                   fcport->port_type != FCT_INITIATOR &&
-                                   fcport->port_type != FCT_BROADCAST) {
-                                       ha->isp_ops->fabric_logout(vha,
-                                           fcport->loop_id,
-                                           fcport->d_id.b.domain,
-                                           fcport->d_id.b.area,
-                                           fcport->d_id.b.al_pa);
-                                       qla2x00_clear_loop_id(fcport);
+                       if (fcport->scan_state == QLA_FCPORT_SCAN) {
+                               if (qla_ini_mode_enabled(base_vha) &&
+                                   atomic_read(&fcport->state) == FCS_ONLINE) {
+                                       qla2x00_mark_device_lost(vha, fcport,
+                                           ql2xplogiabsentdevice, 0);
+                                       if (fcport->loop_id != FC_NO_LOOP_ID &&
+                                           (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
+                                           fcport->port_type != FCT_INITIATOR &&
+                                           fcport->port_type != FCT_BROADCAST) {
+                                               ha->isp_ops->fabric_logout(vha,
+                                                   fcport->loop_id,
+                                                   fcport->d_id.b.domain,
+                                                   fcport->d_id.b.area,
+                                                   fcport->d_id.b.al_pa);
+                                               qla2x00_clear_loop_id(fcport);
+                                       }
+                               } else if (!qla_ini_mode_enabled(base_vha)) {
+                                       /*
+                                        * In target mode, explicitly kill
+                                        * sessions and log out of devices
+                                        * that are gone, so that we don't
+                                        * end up with an initiator using the
+                                        * wrong ACL (if the fabric recycles
+                                        * an FC address and we have a stale
+                                        * session around) and so that we don't
+                                        * report initiators that are no longer
+                                        * on the fabric.
+                                        */
+                                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf077,
+                                           "port gone, logging out/killing session: "
+                                           "%8phC state 0x%x flags 0x%x fc4_type 0x%x "
+                                           "scan_state %d\n",
+                                           fcport->port_name,
+                                           atomic_read(&fcport->state),
+                                           fcport->flags, fcport->fc4_type,
+                                           fcport->scan_state);
+                                       qlt_fc_port_deleted(vha, fcport,
+                                           discovery_gen);
                                }
                        }
                }
@@ -3494,6 +3534,28 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                            (fcport->flags & FCF_LOGIN_NEEDED) == 0)
                                continue;
 
+                       /*
+                        * If we're not an initiator, skip looking for devices
+                        * and logging in.  There's no reason for us to do it,
+                        * and it seems to actively cause problems in target
+                        * mode if we race with the initiator logging into us
+                        * (we might get the "port ID used" status back from
+                        * our login command and log out the initiator, which
+                        * seems to cause havoc).
+                        */
+                       if (!qla_ini_mode_enabled(base_vha)) {
+                               if (fcport->scan_state == QLA_FCPORT_FOUND) {
+                                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf078,
+                                           "port %8phC state 0x%x flags 0x%x fc4_type 0x%x "
+                                           "scan_state %d (initiator mode disabled; skipping "
+                                           "login)\n", fcport->port_name,
+                                           atomic_read(&fcport->state),
+                                           fcport->flags, fcport->fc4_type,
+                                           fcport->scan_state);
+                               }
+                               continue;
+                       }
+
                        if (fcport->loop_id == FC_NO_LOOP_ID) {
                                fcport->loop_id = next_loopid;
                                rval = qla2x00_find_new_loop_id(
@@ -3520,16 +3582,38 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                            test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
                                break;
 
-                       /* Find a new loop ID to use. */
-                       fcport->loop_id = next_loopid;
-                       rval = qla2x00_find_new_loop_id(base_vha, fcport);
-                       if (rval != QLA_SUCCESS) {
-                               /* Ran out of IDs to use */
-                               break;
-                       }
+                       /*
+                        * If we're not an initiator, skip looking for devices
+                        * and logging in.  There's no reason for us to do it,
+                        * and it seems to actively cause problems in target
+                        * mode if we race with the initiator logging into us
+                        * (we might get the "port ID used" status back from
+                        * our login command and log out the initiator, which
+                        * seems to cause havoc).
+                        */
+                       if (qla_ini_mode_enabled(base_vha)) {
+                               /* Find a new loop ID to use. */
+                               fcport->loop_id = next_loopid;
+                               rval = qla2x00_find_new_loop_id(base_vha,
+                                   fcport);
+                               if (rval != QLA_SUCCESS) {
+                                       /* Ran out of IDs to use */
+                                       break;
+                               }
 
-                       /* Login and update database */
-                       qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
+                               /* Login and update database */
+                               qla2x00_fabric_dev_login(vha, fcport,
+                                   &next_loopid);
+                       } else {
+                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf079,
+                                       "new port %8phC state 0x%x flags 0x%x fc4_type "
+                                       "0x%x scan_state %d (initiator mode disabled; "
+                                       "skipping login)\n",
+                                       fcport->port_name,
+                                       atomic_read(&fcport->state),
+                                       fcport->flags, fcport->fc4_type,
+                                       fcport->scan_state);
+                       }
 
                        list_move_tail(&fcport->list, &vha->vp_fcports);
                }
@@ -3725,11 +3809,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        fcport->fp_speed = new_fcport->fp_speed;
 
                        /*
-                        * If address the same and state FCS_ONLINE, nothing
-                        * changed.
+                        * If address the same and state FCS_ONLINE
+                        * (or in target mode), nothing changed.
                         */
                        if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
-                           atomic_read(&fcport->state) == FCS_ONLINE) {
+                           (atomic_read(&fcport->state) == FCS_ONLINE ||
+                            !qla_ini_mode_enabled(base_vha))) {
                                break;
                        }
 
@@ -3749,6 +3834,22 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                         * Log it out if still logged in and mark it for
                         * relogin later.
                         */
+                       if (!qla_ini_mode_enabled(base_vha)) {
+                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf080,
+                                        "port changed FC ID, %8phC"
+                                        " old %x:%x:%x (loop_id 0x%04x)-> new %x:%x:%x\n",
+                                        fcport->port_name,
+                                        fcport->d_id.b.domain,
+                                        fcport->d_id.b.area,
+                                        fcport->d_id.b.al_pa,
+                                        fcport->loop_id,
+                                        new_fcport->d_id.b.domain,
+                                        new_fcport->d_id.b.area,
+                                        new_fcport->d_id.b.al_pa);
+                               fcport->d_id.b24 = new_fcport->d_id.b24;
+                               break;
+                       }
+
                        fcport->d_id.b24 = new_fcport->d_id.b24;
                        fcport->flags |= FCF_LOGIN_NEEDED;
                        if (fcport->loop_id != FC_NO_LOOP_ID &&
@@ -3768,6 +3869,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                if (found)
                        continue;
                /* If device was not in our fcports list, then add it. */
+               new_fcport->scan_state = QLA_FCPORT_FOUND;
                list_add_tail(&new_fcport->list, new_fcports);
 
                /* Allocate a new replacement fcport. */
@@ -4188,6 +4290,14 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
                            atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
                                spin_unlock_irqrestore(&ha->vport_slock, flags);
                                qla2x00_rport_del(fcport);
+
+                               /*
+                                * Release the target mode FC NEXUS in
+                                * qla_target.c, if target mod is enabled.
+                                */
+                               qlt_fc_port_deleted(vha, fcport,
+                                   base_vha->total_fcport_update_gen);
+
                                spin_lock_irqsave(&ha->vport_slock, flags);
                        }
                }
index 36fbd4c7af8f50e52cd0289bc31d9ccfca8bbe24..6f02b26a35cff5b06916273a0bf1c8643f523689 100644 (file)
@@ -1943,6 +1943,9 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
        logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
        logio->control_flags =
            cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
+       if (!sp->fcport->tgt_session ||
+           !sp->fcport->tgt_session->keep_nport_handle)
+               logio->control_flags |= cpu_to_le16(LCF_FREE_NPORT);
        logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
        logio->port_id[0] = sp->fcport->d_id.b.al_pa;
        logio->port_id[1] = sp->fcport->d_id.b.area;
index 02b1c1c5355b948db22e1e69d2ae513387d198fa..b2f713ad90346093b40b515b70be4062666c6b80 100644 (file)
@@ -2415,7 +2415,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
                        *orig_iocb_cnt = mcp->mb[10];
                if (vha->hw->flags.npiv_supported && max_npiv_vports)
                        *max_npiv_vports = mcp->mb[11];
-               if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) && max_fcfs)
+               if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
+                   IS_QLA27XX(vha->hw)) && max_fcfs)
                        *max_fcfs = mcp->mb[12];
        }
 
@@ -3898,7 +3899,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        spin_lock_irqsave(&ha->hardware_lock, flags);
        if (!(rsp->options & BIT_0)) {
                WRT_REG_DWORD(rsp->rsp_q_out, 0);
-               if (!IS_QLA83XX(ha))
+               if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                        WRT_REG_DWORD(rsp->rsp_q_in, 0);
        }
 
@@ -5345,7 +5346,7 @@ qla83xx_restart_nic_firmware(scsi_qla_host_t *vha)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       if (!IS_QLA83XX(ha))
+       if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                return QLA_FUNCTION_FAILED;
 
        ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__);
index a28815b8276f090901498dafaf39d12c97db42eb..8a5cac8448c76518107d95744b39ea76717958f5 100644 (file)
@@ -2504,6 +2504,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
                req_length = REQUEST_ENTRY_CNT_24XX;
                rsp_length = RESPONSE_ENTRY_CNT_2300;
+               ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
                ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
                ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
                ha->gid_list_info_size = 8;
@@ -3229,11 +3230,15 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
                spin_lock_irqsave(vha->host->host_lock, flags);
                fcport->drport = rport;
                spin_unlock_irqrestore(vha->host->host_lock, flags);
+               qlt_do_generation_tick(vha, &base_vha->total_fcport_update_gen);
                set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
                qla2xxx_wake_dpc(base_vha);
        } else {
-               fc_remote_port_delete(rport);
-               qlt_fc_port_deleted(vha, fcport);
+               int now;
+               if (rport)
+                       fc_remote_port_delete(rport);
+               qlt_do_generation_tick(vha, &now);
+               qlt_fc_port_deleted(vha, fcport, now);
        }
 }
 
@@ -3763,8 +3768,11 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        INIT_LIST_HEAD(&vha->vp_fcports);
        INIT_LIST_HEAD(&vha->work_list);
        INIT_LIST_HEAD(&vha->list);
+       INIT_LIST_HEAD(&vha->qla_cmd_list);
+       INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
 
        spin_lock_init(&vha->work_lock);
+       spin_lock_init(&vha->cmd_list_lock);
 
        sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
        ql_dbg(ql_dbg_init, vha, 0x0041,
index 028e8c8a7de9a897ac68ad8c09a2d47be0276f5c..2feb5f38edcd98ec3607f18a020d1cedee5bfc40 100644 (file)
@@ -1697,7 +1697,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha)
 {
        uint32_t led_select_value = 0;
 
-       if (!IS_QLA83XX(ha))
+       if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
                goto out;
 
        if (ha->port_no == 0)
index b749026aa592445d70dd51056314ff29965578ca..58651ecbd88c206e0be3b996c007baeaddc8cb19 100644 (file)
@@ -113,6 +113,11 @@ static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
 static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
        struct atio_from_isp *atio, uint16_t status, int qfull);
 static void qlt_disable_vha(struct scsi_qla_host *vha);
+static void qlt_clear_tgt_db(struct qla_tgt *tgt);
+static void qlt_send_notify_ack(struct scsi_qla_host *vha,
+       struct imm_ntfy_from_isp *ntfy,
+       uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
+       uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
 /*
  * Global Variables
  */
@@ -122,6 +127,16 @@ static struct workqueue_struct *qla_tgt_wq;
 static DEFINE_MUTEX(qla_tgt_mutex);
 static LIST_HEAD(qla_tgt_glist);
 
+/* This API intentionally takes dest as a parameter, rather than returning
+ * int value to avoid caller forgetting to issue wmb() after the store */
+void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest)
+{
+       scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev);
+       *dest = atomic_inc_return(&base_vha->generation_tick);
+       /* memory barrier */
+       wmb();
+}
+
 /* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */
 static struct qla_tgt_sess *qlt_find_sess_by_port_name(
        struct qla_tgt *tgt,
@@ -381,14 +396,73 @@ static void qlt_free_session_done(struct work_struct *work)
        struct qla_tgt *tgt = sess->tgt;
        struct scsi_qla_host *vha = sess->vha;
        struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+       bool logout_started = false;
+       fc_port_t fcport;
+
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
+               "%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
+               " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+               __func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
+               sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
+               sess->logout_on_delete, sess->keep_nport_handle,
+               sess->plogi_ack_needed);
 
        BUG_ON(!tgt);
+
+       if (sess->logout_on_delete) {
+               int rc;
+
+               memset(&fcport, 0, sizeof(fcport));
+               fcport.loop_id = sess->loop_id;
+               fcport.d_id = sess->s_id;
+               memcpy(fcport.port_name, sess->port_name, WWN_SIZE);
+               fcport.vha = vha;
+               fcport.tgt_session = sess;
+
+               rc = qla2x00_post_async_logout_work(vha, &fcport, NULL);
+               if (rc != QLA_SUCCESS)
+                       ql_log(ql_log_warn, vha, 0xf085,
+                              "Schedule logo failed sess %p rc %d\n",
+                              sess, rc);
+               else
+                       logout_started = true;
+       }
+
        /*
         * Release the target session for FC Nexus from fabric module code.
         */
        if (sess->se_sess != NULL)
                ha->tgt.tgt_ops->free_session(sess);
 
+       if (logout_started) {
+               bool traced = false;
+
+               while (!ACCESS_ONCE(sess->logout_completed)) {
+                       if (!traced) {
+                               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf086,
+                                       "%s: waiting for sess %p logout\n",
+                                       __func__, sess);
+                               traced = true;
+                       }
+                       msleep(100);
+               }
+
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf087,
+                       "%s: sess %p logout completed\n",
+                       __func__, sess);
+       }
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+
+       if (sess->plogi_ack_needed)
+               qlt_send_notify_ack(vha, &sess->tm_iocb,
+                                   0, 0, 0, 0, 0, 0);
+
+       list_del(&sess->sess_list_entry);
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001,
            "Unregistration of sess %p finished\n", sess);
 
@@ -409,9 +483,9 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
 
        vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess);
 
-       list_del(&sess->sess_list_entry);
-       if (sess->deleted)
-               list_del(&sess->del_list_entry);
+       if (!list_empty(&sess->del_list_entry))
+               list_del_init(&sess->del_list_entry);
+       sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
 
        INIT_WORK(&sess->free_work, qlt_free_session_done);
        schedule_work(&sess->free_work);
@@ -431,10 +505,10 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 
        loop_id = le16_to_cpu(n->u.isp24.nport_handle);
        if (loop_id == 0xFFFF) {
-#if 0 /* FIXME: Re-enable Global event handling.. */
                /* Global event */
-               atomic_inc(&ha->tgt.qla_tgt->tgt_global_resets_count);
-               qlt_clear_tgt_db(ha->tgt.qla_tgt);
+               atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+               qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+#if 0 /* FIXME: do we need to choose a session here? */
                if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
                        sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
                            typeof(*sess), sess_list_entry);
@@ -489,27 +563,38 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
        struct qla_tgt *tgt = sess->tgt;
        uint32_t dev_loss_tmo = tgt->ha->port_down_retry_count + 5;
 
-       if (sess->deleted)
-               return;
+       if (sess->deleted) {
+               /* Upgrade to unconditional deletion in case it was temporary */
+               if (immediate && sess->deleted == QLA_SESS_DELETION_PENDING)
+                       list_del(&sess->del_list_entry);
+               else
+                       return;
+       }
 
        ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
            "Scheduling sess %p for deletion\n", sess);
-       list_add_tail(&sess->del_list_entry, &tgt->del_sess_list);
-       sess->deleted = 1;
 
-       if (immediate)
+       if (immediate) {
                dev_loss_tmo = 0;
+               sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
+               list_add(&sess->del_list_entry, &tgt->del_sess_list);
+       } else {
+               sess->deleted = QLA_SESS_DELETION_PENDING;
+               list_add_tail(&sess->del_list_entry, &tgt->del_sess_list);
+       }
 
        sess->expires = jiffies + dev_loss_tmo * HZ;
 
        ql_dbg(ql_dbg_tgt, sess->vha, 0xe048,
-           "qla_target(%d): session for port %8phC (loop ID %d) scheduled for "
-           "deletion in %u secs (expires: %lu) immed: %d\n",
-           sess->vha->vp_idx, sess->port_name, sess->loop_id, dev_loss_tmo,
-           sess->expires, immediate);
+           "qla_target(%d): session for port %8phC (loop ID %d s_id %02x:%02x:%02x)"
+           " scheduled for deletion in %u secs (expires: %lu) immed: %d, logout: %d, gen: %#x\n",
+           sess->vha->vp_idx, sess->port_name, sess->loop_id,
+           sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
+           dev_loss_tmo, sess->expires, immediate, sess->logout_on_delete,
+           sess->generation);
 
        if (immediate)
-               schedule_delayed_work(&tgt->sess_del_work, 0);
+               mod_delayed_work(system_wq, &tgt->sess_del_work, 0);
        else
                schedule_delayed_work(&tgt->sess_del_work,
                    sess->expires - jiffies);
@@ -578,9 +663,9 @@ out_free_id_list:
 /* ha->hardware_lock supposed to be held on entry */
 static void qlt_undelete_sess(struct qla_tgt_sess *sess)
 {
-       BUG_ON(!sess->deleted);
+       BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
 
-       list_del(&sess->del_list_entry);
+       list_del_init(&sess->del_list_entry);
        sess->deleted = 0;
 }
 
@@ -599,7 +684,9 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
                    del_list_entry);
                elapsed = jiffies;
                if (time_after_eq(elapsed, sess->expires)) {
-                       qlt_undelete_sess(sess);
+                       /* No turning back */
+                       list_del_init(&sess->del_list_entry);
+                       sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
 
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004,
                            "Timeout: sess %p about to be deleted\n",
@@ -643,6 +730,13 @@ static struct qla_tgt_sess *qlt_create_sess(
                            fcport->d_id.b.al_pa, fcport->d_id.b.area,
                            fcport->loop_id);
 
+                       /* Cannot undelete at this point */
+                       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+                               spin_unlock_irqrestore(&ha->hardware_lock,
+                                   flags);
+                               return NULL;
+                       }
+
                        if (sess->deleted)
                                qlt_undelete_sess(sess);
 
@@ -652,6 +746,9 @@ static struct qla_tgt_sess *qlt_create_sess(
 
                        if (sess->local && !local)
                                sess->local = 0;
+
+                       qlt_do_generation_tick(vha, &sess->generation);
+
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
                        return sess;
@@ -673,6 +770,14 @@ static struct qla_tgt_sess *qlt_create_sess(
        sess->s_id = fcport->d_id;
        sess->loop_id = fcport->loop_id;
        sess->local = local;
+       INIT_LIST_HEAD(&sess->del_list_entry);
+
+       /* Under normal circumstances we want to logout from firmware when
+        * session eventually ends and release corresponding nport handle.
+        * In the exception cases (e.g. when new PLOGI is waiting) corresponding
+        * code will adjust these flags as necessary. */
+       sess->logout_on_delete = 1;
+       sess->keep_nport_handle = 0;
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006,
            "Adding sess %p to tgt %p via ->check_initiator_node_acl()\n",
@@ -705,6 +810,7 @@ static struct qla_tgt_sess *qlt_create_sess(
        spin_lock_irqsave(&ha->hardware_lock, flags);
        list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
        vha->vha_tgt.qla_tgt->sess_count++;
+       qlt_do_generation_tick(vha, &sess->generation);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
@@ -718,7 +824,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 }
 
 /*
- * Called from drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port()
+ * Called from qla2x00_reg_remote_port()
  */
 void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
@@ -750,6 +856,10 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
                mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
+       } else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               /* Point of no return */
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return;
        } else {
                kref_get(&sess->se_sess->sess_kref);
 
@@ -780,27 +890,36 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
-void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
+/*
+ * max_gen - specifies maximum session generation
+ * at which this deletion requestion is still valid
+ */
+void
+qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_sess *sess;
-       unsigned long flags;
 
        if (!vha->hw->tgt.tgt_ops)
                return;
 
-       if (!tgt || (fcport->port_type != FCT_INITIATOR))
+       if (!tgt)
                return;
 
-       spin_lock_irqsave(&ha->hardware_lock, flags);
        if (tgt->tgt_stop) {
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return;
        }
        sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
        if (!sess) {
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return;
+       }
+
+       if (max_gen - sess->generation < 0) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
+                   "Ignoring stale deletion request for se_sess %p / sess %p"
+                   " for port %8phC, req_gen %d, sess_gen %d\n",
+                   sess->se_sess, sess, sess->port_name, max_gen,
+                   sess->generation);
                return;
        }
 
@@ -808,7 +927,6 @@ void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
 
        sess->local = 1;
        qlt_schedule_sess_for_deletion(sess, false);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
 static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -1175,6 +1293,70 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
            FCP_TMF_CMPL, true);
 }
 
+static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
+{
+       struct qla_tgt_sess_op *op;
+       struct qla_tgt_cmd *cmd;
+
+       spin_lock(&vha->cmd_list_lock);
+
+       list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
+               if (tag == op->atio.u.isp24.exchange_addr) {
+                       op->aborted = true;
+                       spin_unlock(&vha->cmd_list_lock);
+                       return 1;
+               }
+       }
+
+       list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+               if (tag == cmd->atio.u.isp24.exchange_addr) {
+                       cmd->state = QLA_TGT_STATE_ABORTED;
+                       spin_unlock(&vha->cmd_list_lock);
+                       return 1;
+               }
+       }
+
+       spin_unlock(&vha->cmd_list_lock);
+       return 0;
+}
+
+/* drop cmds for the given lun
+ * XXX only looks for cmds on the port through which lun reset was recieved
+ * XXX does not go through the list of other port (which may have cmds
+ *     for the same lun)
+ */
+static void abort_cmds_for_lun(struct scsi_qla_host *vha,
+                               uint32_t lun, uint8_t *s_id)
+{
+       struct qla_tgt_sess_op *op;
+       struct qla_tgt_cmd *cmd;
+       uint32_t key;
+
+       key = sid_to_key(s_id);
+       spin_lock(&vha->cmd_list_lock);
+       list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
+               uint32_t op_key;
+               uint32_t op_lun;
+
+               op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id);
+               op_lun = scsilun_to_int(
+                       (struct scsi_lun *)&op->atio.u.isp24.fcp_cmnd.lun);
+               if (op_key == key && op_lun == lun)
+                       op->aborted = true;
+       }
+       list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+               uint32_t cmd_key;
+               uint32_t cmd_lun;
+
+               cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
+               cmd_lun = scsilun_to_int(
+                       (struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
+               if (cmd_key == key && cmd_lun == lun)
+                       cmd->state = QLA_TGT_STATE_ABORTED;
+       }
+       spin_unlock(&vha->cmd_list_lock);
+}
+
 /* ha->hardware_lock supposed to be held on entry */
 static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
        struct abts_recv_from_24xx *abts, struct qla_tgt_sess *sess)
@@ -1199,8 +1381,19 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
        }
        spin_unlock(&se_sess->sess_cmd_lock);
 
-       if (!found_lun)
-               return -ENOENT;
+       /* 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(vha, 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;
+               }
+       }
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
            "qla_target(%d): task abort (tag=%d)\n",
@@ -1284,6 +1477,11 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
                return;
        }
 
+       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
+               return;
+       }
+
        rc = __qlt_24xx_handle_abts(vha, abts, sess);
        if (rc != 0) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054,
@@ -1726,20 +1924,6 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd,
        struct qla_hw_data *ha = vha->hw;
        struct se_cmd *se_cmd = &cmd->se_cmd;
 
-       if (unlikely(cmd->aborted)) {
-               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
-                      "qla_target(%d): terminating exchange for aborted cmd=%p (se_cmd=%p, tag=%lld)",
-                      vha->vp_idx, cmd, se_cmd, se_cmd->tag);
-
-               cmd->state = QLA_TGT_STATE_ABORTED;
-               cmd->cmd_flags |= BIT_6;
-
-               qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
-
-               /* !! At this point cmd could be already freed !! */
-               return QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED;
-       }
-
        prm->cmd = cmd;
        prm->tgt = tgt;
        prm->rq_result = scsi_status;
@@ -2301,6 +2485,19 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
        unsigned long flags = 0;
        int res;
 
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       if (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               cmd->state = QLA_TGT_STATE_PROCESSED;
+               if (cmd->sess->logout_completed)
+                       /* no need to terminate. FW already freed exchange. */
+                       qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
+               else
+                       qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
        memset(&prm, 0, sizeof(prm));
        qlt_check_srr_debug(cmd, &xmit_type);
 
@@ -2313,9 +2510,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
        res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status,
            &full_req_cnt);
        if (unlikely(res != 0)) {
-               if (res == QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED)
-                       return 0;
-
                return res;
        }
 
@@ -2345,9 +2539,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
                res = qlt_build_ctio_crc2_pkt(&prm, vha);
        else
                res = qlt_24xx_build_ctio_pkt(&prm, vha);
-       if (unlikely(res != 0))
+       if (unlikely(res != 0)) {
+               vha->req->cnt += full_req_cnt;
                goto out_unmap_unlock;
-
+       }
 
        pkt = (struct ctio7_to_24xx *)prm.pkt;
 
@@ -2461,7 +2656,8 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+       if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+           (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
                /*
                 * Either a chip reset is active or this request was from
                 * previous life, just abort the processing.
@@ -2485,8 +2681,11 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
        else
                res = qlt_24xx_build_ctio_pkt(&prm, vha);
 
-       if (unlikely(res != 0))
+       if (unlikely(res != 0)) {
+               vha->req->cnt += prm.req_cnt;
                goto out_unlock_free_unmap;
+       }
+
        pkt = (struct ctio7_to_24xx *)prm.pkt;
        pkt->u.status0.flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT |
            CTIO7_FLAGS_STATUS_MODE_0);
@@ -2649,6 +2848,89 @@ out:
 }
 
 
+/* If hardware_lock held on entry, might drop it, then reaquire */
+/* This function sends the appropriate CTIO to ISP 2xxx or 24xx */
+static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+       struct imm_ntfy_from_isp *ntfy)
+{
+       struct nack_to_isp *nack;
+       struct qla_hw_data *ha = vha->hw;
+       request_t *pkt;
+       int ret = 0;
+
+       ql_dbg(ql_dbg_tgt_tmr, vha, 0xe01c,
+           "Sending TERM ELS CTIO (ha=%p)\n", ha);
+
+       pkt = (request_t *)qla2x00_alloc_iocbs_ready(vha, NULL);
+       if (pkt == NULL) {
+               ql_dbg(ql_dbg_tgt, vha, 0xe080,
+                   "qla_target(%d): %s failed: unable to allocate "
+                   "request packet\n", vha->vp_idx, __func__);
+               return -ENOMEM;
+       }
+
+       pkt->entry_type = NOTIFY_ACK_TYPE;
+       pkt->entry_count = 1;
+       pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
+
+       nack = (struct nack_to_isp *)pkt;
+       nack->ox_id = ntfy->ox_id;
+
+       nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle;
+       if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) {
+               nack->u.isp24.flags = ntfy->u.isp24.flags &
+                       __constant_cpu_to_le32(NOTIFY24XX_FLAGS_PUREX_IOCB);
+       }
+
+       /* terminate */
+       nack->u.isp24.flags |=
+               __constant_cpu_to_le16(NOTIFY_ACK_FLAGS_TERMINATE);
+
+       nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id;
+       nack->u.isp24.status = ntfy->u.isp24.status;
+       nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode;
+       nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle;
+       nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address;
+       nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs;
+       nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui;
+       nack->u.isp24.vp_index = ntfy->u.isp24.vp_index;
+
+       qla2x00_start_iocbs(vha, vha->req);
+       return ret;
+}
+
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+       struct imm_ntfy_from_isp *imm, int ha_locked)
+{
+       unsigned long flags = 0;
+       int rc;
+
+       if (qlt_issue_marker(vha, ha_locked) < 0)
+               return;
+
+       if (ha_locked) {
+               rc = __qlt_send_term_imm_notif(vha, imm);
+
+#if 0  /* Todo  */
+               if (rc == -ENOMEM)
+                       qlt_alloc_qfull_cmd(vha, imm, 0, 0);
+#endif
+               goto done;
+       }
+
+       spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+       rc = __qlt_send_term_imm_notif(vha, imm);
+
+#if 0  /* Todo */
+       if (rc == -ENOMEM)
+               qlt_alloc_qfull_cmd(vha, imm, 0, 0);
+#endif
+
+done:
+       if (!ha_locked)
+               spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+}
+
 /* If hardware_lock held on entry, might drop it, then reaquire */
 /* This function sends the appropriate CTIO to ISP 2xxx or 24xx */
 static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
@@ -2715,7 +2997,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 static void qlt_send_term_exchange(struct scsi_qla_host *vha,
        struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
 {
-       unsigned long flags;
+       unsigned long flags = 0;
        int rc;
 
        if (qlt_issue_marker(vha, ha_locked) < 0)
@@ -2731,17 +3013,18 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
        rc = __qlt_send_term_exchange(vha, cmd, atio);
        if (rc == -ENOMEM)
                qlt_alloc_qfull_cmd(vha, atio, 0, 0);
-       spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 
 done:
        if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
            !cmd->cmd_sent_to_fw)) {
-               if (!ha_locked && !in_interrupt())
-                       msleep(250); /* just in case */
-
-               qlt_unmap_sg(vha, cmd);
+               if (cmd->sg_mapped)
+                       qlt_unmap_sg(vha, cmd);
                vha->hw->tgt.tgt_ops->free_cmd(cmd);
        }
+
+       if (!ha_locked)
+               spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+
        return;
 }
 
@@ -2792,6 +3075,24 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
 
 }
 
+void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+{
+       struct qla_tgt *tgt = cmd->tgt;
+       struct scsi_qla_host *vha = tgt->vha;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
+           "qla_target(%d): terminating exchange for aborted cmd=%p "
+           "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
+           se_cmd->tag);
+
+       cmd->state = QLA_TGT_STATE_ABORTED;
+       cmd->cmd_flags |= BIT_6;
+
+       qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+}
+EXPORT_SYMBOL(qlt_abort_cmd);
+
 void qlt_free_cmd(struct qla_tgt_cmd *cmd)
 {
        struct qla_tgt_sess *sess = cmd->sess;
@@ -3015,7 +3316,7 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
                dump_stack();
        }
 
-       cmd->cmd_flags |= BIT_12;
+       cmd->cmd_flags |= BIT_17;
        ha->tgt.tgt_ops->free_cmd(cmd);
 }
 
@@ -3177,7 +3478,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 skip_term:
 
        if (cmd->state == QLA_TGT_STATE_PROCESSED) {
-               ;
+               cmd->cmd_flags |= BIT_12;
        } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
                int rx_status = 0;
 
@@ -3191,9 +3492,11 @@ skip_term:
                ha->tgt.tgt_ops->handle_data(cmd);
                return;
        } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+               cmd->cmd_flags |= BIT_18;
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
                  "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
        } else {
+               cmd->cmd_flags |= BIT_19;
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c,
                    "qla_target(%d): A command in state (%d) should "
                    "not return a CTIO complete\n", vha->vp_idx, cmd->state);
@@ -3205,7 +3508,6 @@ skip_term:
                dump_stack();
        }
 
-
        ha->tgt.tgt_ops->free_cmd(cmd);
 }
 
@@ -3263,6 +3565,13 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
        if (tgt->tgt_stop)
                goto out_term;
 
+       if (cmd->state == QLA_TGT_STATE_ABORTED) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
+                   "cmd with tag %u is aborted\n",
+                   cmd->atio.u.isp24.exchange_addr);
+               goto out_term;
+       }
+
        cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
        cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
        cmd->unpacked_lun = scsilun_to_int(
@@ -3316,6 +3625,12 @@ out_term:
 static void qlt_do_work(struct work_struct *work)
 {
        struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+       scsi_qla_host_t *vha = cmd->vha;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vha->cmd_list_lock, flags);
+       list_del(&cmd->cmd_list);
+       spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
 
        __qlt_do_work(cmd);
 }
@@ -3345,6 +3660,11 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
        cmd->loop_id = sess->loop_id;
        cmd->conf_compl_supported = sess->conf_compl_supported;
 
+       cmd->cmd_flags = 0;
+       cmd->jiffies_at_alloc = get_jiffies_64();
+
+       cmd->reset_count = vha->hw->chip_reset;
+
        return cmd;
 }
 
@@ -3362,14 +3682,25 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
        unsigned long flags;
        uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id;
 
+       spin_lock_irqsave(&vha->cmd_list_lock, flags);
+       list_del(&op->cmd_list);
+       spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
+
+       if (op->aborted) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf083,
+                   "sess_op with tag %u is aborted\n",
+                   op->atio.u.isp24.exchange_addr);
+               goto out_term;
+       }
+
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
-               "qla_target(%d): Unable to find wwn login"
-               " (s_id %x:%x:%x), trying to create it manually\n",
-               vha->vp_idx, s_id[0], s_id[1], s_id[2]);
+           "qla_target(%d): Unable to find wwn login"
+           " (s_id %x:%x:%x), trying to create it manually\n",
+           vha->vp_idx, s_id[0], s_id[1], s_id[2]);
 
        if (op->atio.u.raw.entry_count > 1) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
-                       "Dropping multy entry atio %p\n", &op->atio);
+                   "Dropping multy entry atio %p\n", &op->atio);
                goto out_term;
        }
 
@@ -3434,10 +3765,25 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 
                memcpy(&op->atio, atio, sizeof(*atio));
                op->vha = vha;
+
+               spin_lock(&vha->cmd_list_lock);
+               list_add_tail(&op->cmd_list, &vha->qla_sess_op_cmd_list);
+               spin_unlock(&vha->cmd_list_lock);
+
                INIT_WORK(&op->work, qlt_create_sess_from_atio);
                queue_work(qla_tgt_wq, &op->work);
                return 0;
        }
+
+       /* Another WWN used to have our s_id. Our PLOGI scheduled its
+        * session deletion, but it's still in sess_del_work wq */
+       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+               ql_dbg(ql_dbg_io, vha, 0x3061,
+                   "New command while old session %p is being deleted\n",
+                   sess);
+               return -EFAULT;
+       }
+
        /*
         * Do kref_get() before returning + dropping qla_hw_data->hardware_lock.
         */
@@ -3451,13 +3797,13 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
                return -ENOMEM;
        }
 
-       cmd->cmd_flags = 0;
-       cmd->jiffies_at_alloc = get_jiffies_64();
-
-       cmd->reset_count = vha->hw->chip_reset;
-
        cmd->cmd_in_wq = 1;
        cmd->cmd_flags |= BIT_0;
+
+       spin_lock(&vha->cmd_list_lock);
+       list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
+       spin_unlock(&vha->cmd_list_lock);
+
        INIT_WORK(&cmd->work, qlt_do_work);
        queue_work(qla_tgt_wq, &cmd->work);
        return 0;
@@ -3471,6 +3817,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
        struct scsi_qla_host *vha = sess->vha;
        struct qla_hw_data *ha = vha->hw;
        struct qla_tgt_mgmt_cmd *mcmd;
+       struct atio_from_isp *a = (struct atio_from_isp *)iocb;
        int res;
        uint8_t tmr_func;
 
@@ -3511,6 +3858,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
                ql_dbg(ql_dbg_tgt_tmr, vha, 0x10002,
                    "qla_target(%d): LUN_RESET received\n", sess->vha->vp_idx);
                tmr_func = TMR_LUN_RESET;
+               abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id);
                break;
 
        case QLA_TGT_CLEAR_TS:
@@ -3599,6 +3947,9 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
                    sizeof(struct atio_from_isp));
        }
 
+       if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)
+               return -EFAULT;
+
        return qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
 }
 
@@ -3664,22 +4015,280 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
        return __qlt_abort_task(vha, iocb, sess);
 }
 
+void qlt_logo_completion_handler(fc_port_t *fcport, int rc)
+{
+       if (fcport->tgt_session) {
+               if (rc != MBS_COMMAND_COMPLETE) {
+                       ql_dbg(ql_dbg_tgt_mgt, fcport->vha, 0xf093,
+                               "%s: se_sess %p / sess %p from"
+                               " port %8phC loop_id %#04x s_id %02x:%02x:%02x"
+                               " LOGO failed: %#x\n",
+                               __func__,
+                               fcport->tgt_session->se_sess,
+                               fcport->tgt_session,
+                               fcport->port_name, fcport->loop_id,
+                               fcport->d_id.b.domain, fcport->d_id.b.area,
+                               fcport->d_id.b.al_pa, rc);
+               }
+
+               fcport->tgt_session->logout_completed = 1;
+       }
+}
+
+static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
+    struct imm_ntfy_from_isp *b)
+{
+       struct imm_ntfy_from_isp tmp;
+       memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
+       memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
+       memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
+}
+
+/*
+* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
+*
+* Schedules sessions with matching port_id/loop_id but different wwn for
+* deletion. Returns existing session with matching wwn if present.
+* Null otherwise.
+*/
+static struct qla_tgt_sess *
+qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
+    port_id_t port_id, uint16_t loop_id)
+{
+       struct qla_tgt_sess *sess = NULL, *other_sess;
+       uint64_t other_wwn;
+
+       list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
+
+               other_wwn = wwn_to_u64(other_sess->port_name);
+
+               if (wwn == other_wwn) {
+                       WARN_ON(sess);
+                       sess = other_sess;
+                       continue;
+               }
+
+               /* find other sess with nport_id collision */
+               if (port_id.b24 == other_sess->s_id.b24) {
+                       if (loop_id != other_sess->loop_id) {
+                               ql_dbg(ql_dbg_tgt_tmr, tgt->vha, 0x1000c,
+                                   "Invalidating sess %p loop_id %d wwn %llx.\n",
+                                   other_sess, other_sess->loop_id, other_wwn);
+
+                               /*
+                                * logout_on_delete is set by default, but another
+                                * session that has the same s_id/loop_id combo
+                                * might have cleared it when requested this session
+                                * deletion, so don't touch it
+                                */
+                               qlt_schedule_sess_for_deletion(other_sess, true);
+                       } else {
+                               /*
+                                * Another wwn used to have our s_id/loop_id
+                                * combo - kill the session, but don't log out
+                                */
+                               sess->logout_on_delete = 0;
+                               qlt_schedule_sess_for_deletion(other_sess,
+                                   true);
+                       }
+                       continue;
+               }
+
+               /* find other sess with nport handle collision */
+               if (loop_id == other_sess->loop_id) {
+                       ql_dbg(ql_dbg_tgt_tmr, tgt->vha, 0x1000d,
+                              "Invalidating sess %p loop_id %d wwn %llx.\n",
+                              other_sess, other_sess->loop_id, other_wwn);
+
+                       /* Same loop_id but different s_id
+                        * Ok to kill and logout */
+                       qlt_schedule_sess_for_deletion(other_sess, true);
+               }
+       }
+
+       return sess;
+}
+
+/* Abort any commands for this s_id waiting on qla_tgt_wq workqueue */
+static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
+{
+       struct qla_tgt_sess_op *op;
+       struct qla_tgt_cmd *cmd;
+       uint32_t key;
+       int count = 0;
+
+       key = (((u32)s_id->b.domain << 16) |
+              ((u32)s_id->b.area   <<  8) |
+              ((u32)s_id->b.al_pa));
+
+       spin_lock(&vha->cmd_list_lock);
+       list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
+               uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id);
+               if (op_key == key) {
+                       op->aborted = true;
+                       count++;
+               }
+       }
+       list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+               uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
+               if (cmd_key == key) {
+                       cmd->state = QLA_TGT_STATE_ABORTED;
+                       count++;
+               }
+       }
+       spin_unlock(&vha->cmd_list_lock);
+
+       return count;
+}
+
 /*
  * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
  */
 static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
        struct imm_ntfy_from_isp *iocb)
 {
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
+       struct qla_hw_data *ha = vha->hw;
+       struct qla_tgt_sess *sess = NULL;
+       uint64_t wwn;
+       port_id_t port_id;
+       uint16_t loop_id;
+       uint16_t wd3_lo;
        int res = 0;
 
+       wwn = wwn_to_u64(iocb->u.isp24.port_name);
+
+       port_id.b.domain = iocb->u.isp24.port_id[2];
+       port_id.b.area   = iocb->u.isp24.port_id[1];
+       port_id.b.al_pa  = iocb->u.isp24.port_id[0];
+       port_id.b.rsvd_1 = 0;
+
+       loop_id = le16_to_cpu(iocb->u.isp24.nport_handle);
+
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026,
            "qla_target(%d): Port ID: 0x%3phC ELS opcode: 0x%02x\n",
            vha->vp_idx, iocb->u.isp24.port_id, iocb->u.isp24.status_subcode);
 
+       /* res = 1 means ack at the end of thread
+        * res = 0 means ack async/later.
+        */
        switch (iocb->u.isp24.status_subcode) {
        case ELS_PLOGI:
-       case ELS_FLOGI:
+
+               /* Mark all stale commands in qla_tgt_wq for deletion */
+               abort_cmds_for_s_id(vha, &port_id);
+
+               if (wwn)
+                       sess = qlt_find_sess_invalidate_other(tgt, wwn,
+                           port_id, loop_id);
+
+               if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+                       res = 1;
+                       break;
+               }
+
+               if (sess->plogi_ack_needed) {
+                       /*
+                        * Initiator sent another PLOGI before last PLOGI could
+                        * finish. Swap plogi iocbs and terminate old one
+                        * without acking, new one will get acked when session
+                        * deletion completes.
+                        */
+                       ql_log(ql_log_warn, sess->vha, 0xf094,
+                           "sess %p received double plogi.\n", sess);
+
+                       qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
+
+                       qlt_send_term_imm_notif(vha, iocb, 1);
+
+                       res = 0;
+                       break;
+               }
+
+               res = 0;
+
+               /*
+                * Save immediate Notif IOCB for Ack when sess is done
+                * and being deleted.
+                */
+               memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
+               sess->plogi_ack_needed  = 1;
+
+                /*
+                 * Under normal circumstances we want to release nport handle
+                 * during LOGO process to avoid nport handle leaks inside FW.
+                 * The exception is when LOGO is done while another PLOGI with
+                 * the same nport handle is waiting as might be the case here.
+                 * Note: there is always a possibily of a race where session
+                 * deletion has already started for other reasons (e.g. ACL
+                 * removal) and now PLOGI arrives:
+                 * 1. if PLOGI arrived in FW after nport handle has been freed,
+                 *    FW must have assigned this PLOGI a new/same handle and we
+                 *    can proceed ACK'ing it as usual when session deletion
+                 *    completes.
+                 * 2. if PLOGI arrived in FW before LOGO with LCF_FREE_NPORT
+                 *    bit reached it, the handle has now been released. We'll
+                 *    get an error when we ACK this PLOGI. Nothing will be sent
+                 *    back to initiator. Initiator should eventually retry
+                 *    PLOGI and situation will correct itself.
+                 */
+               sess->keep_nport_handle = ((sess->loop_id == loop_id) &&
+                                          (sess->s_id.b24 == port_id.b24));
+               qlt_schedule_sess_for_deletion(sess, true);
+               break;
+
        case ELS_PRLI:
+               wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
+
+               if (wwn)
+                       sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
+                           loop_id);
+
+               if (sess != NULL) {
+                       if (sess->deleted) {
+                               /*
+                                * Impatient initiator sent PRLI before last
+                                * PLOGI could finish. Will force him to re-try,
+                                * while last one finishes.
+                                */
+                               ql_log(ql_log_warn, sess->vha, 0xf095,
+                                   "sess %p PRLI received, before plogi ack.\n",
+                                   sess);
+                               qlt_send_term_imm_notif(vha, iocb, 1);
+                               res = 0;
+                               break;
+                       }
+
+                       /*
+                        * This shouldn't happen under normal circumstances,
+                        * since we have deleted the old session during PLOGI
+                        */
+                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf096,
+                           "PRLI (loop_id %#04x) for existing sess %p (loop_id %#04x)\n",
+                           sess->loop_id, sess, iocb->u.isp24.nport_handle);
+
+                       sess->local = 0;
+                       sess->loop_id = loop_id;
+                       sess->s_id = port_id;
+
+                       if (wd3_lo & BIT_7)
+                               sess->conf_compl_supported = 1;
+
+               }
+               res = 1; /* send notify ack */
+
+               /* Make session global (not used in fabric mode) */
+               if (ha->current_topology != ISP_CFG_F) {
+                       set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+                       set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+                       qla2xxx_wake_dpc(vha);
+               } else {
+                       /* todo: else - create sess here. */
+                       res = 1; /* send notify ack */
+               }
+
+               break;
+
        case ELS_LOGO:
        case ELS_PRLO:
                res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS);
@@ -3697,6 +4306,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
                break;
        }
 
+       case ELS_FLOGI: /* should never happen */
        default:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf061,
                    "qla_target(%d): Unsupported ELS command %x "
@@ -5012,6 +5622,11 @@ static void qlt_abort_work(struct qla_tgt *tgt,
                if (!sess)
                        goto out_term;
        } else {
+               if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+                       sess = NULL;
+                       goto out_term;
+               }
+
                kref_get(&sess->se_sess->sess_kref);
        }
 
@@ -5066,6 +5681,11 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
                if (!sess)
                        goto out_term;
        } else {
+               if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
+                       sess = NULL;
+                       goto out_term;
+               }
+
                kref_get(&sess->se_sess->sess_kref);
        }
 
@@ -5552,6 +6172,7 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
 
        /* Adjust ring index */
        WRT_REG_DWORD(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index);
+       RD_REG_DWORD_RELAXED(ISP_ATIO_Q_OUT(vha));
 }
 
 void
@@ -5793,7 +6414,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha)
        if (!QLA_TGT_MODE_ENABLED())
                return;
 
-       if  (ha->mqenable || IS_QLA83XX(ha)) {
+       if  (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
                ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in;
                ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out;
        } else {
index 985d76dd706b71b3da1b3685169a21c24af90fa0..bca584ae45b7eccc3da35a11c9583c324524a802 100644 (file)
@@ -167,7 +167,24 @@ struct imm_ntfy_from_isp {
                        uint32_t srr_rel_offs;
                        uint16_t srr_ui;
                        uint16_t srr_ox_id;
-                       uint8_t  reserved_4[19];
+                       union {
+                               struct {
+                                       uint8_t node_name[8];
+                               } plogi; /* PLOGI/ADISC/PDISC */
+                               struct {
+                                       /* PRLI word 3 bit 0-15 */
+                                       uint16_t wd3_lo;
+                                       uint8_t resv0[6];
+                               } prli;
+                               struct {
+                                       uint8_t port_id[3];
+                                       uint8_t resv1;
+                                       uint16_t nport_handle;
+                                       uint16_t resv2;
+                               } req_els;
+                       } u;
+                       uint8_t port_name[8];
+                       uint8_t resv3[3];
                        uint8_t  vp_index;
                        uint32_t reserved_5;
                        uint8_t  port_id[3];
@@ -234,6 +251,7 @@ struct nack_to_isp {
        uint8_t  reserved[2];
        uint16_t ox_id;
 } __packed;
+#define NOTIFY_ACK_FLAGS_TERMINATE     BIT_3
 #define NOTIFY_ACK_SRR_FLAGS_ACCEPT    0
 #define NOTIFY_ACK_SRR_FLAGS_REJECT    1
 
@@ -790,13 +808,6 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
 #define        FC_TM_REJECT                4
 #define FC_TM_FAILED                5
 
-/*
- * Error code of qlt_pre_xmit_response() meaning that cmd's exchange was
- * terminated, so no more actions is needed and success should be returned
- * to target.
- */
-#define QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED      0x1717
-
 #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G)
 #define pci_dma_lo32(a) (a & 0xffffffff)
 #define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff)
@@ -874,6 +885,15 @@ struct qla_tgt_sess_op {
        struct scsi_qla_host *vha;
        struct atio_from_isp atio;
        struct work_struct work;
+       struct list_head cmd_list;
+       bool aborted;
+};
+
+enum qla_sess_deletion {
+       QLA_SESS_DELETION_NONE          = 0,
+       QLA_SESS_DELETION_PENDING       = 1, /* hopefully we can get rid of
+                                             * this one */
+       QLA_SESS_DELETION_IN_PROGRESS   = 2,
 };
 
 /*
@@ -884,8 +904,15 @@ struct qla_tgt_sess {
        port_id_t s_id;
 
        unsigned int conf_compl_supported:1;
-       unsigned int deleted:1;
+       unsigned int deleted:2;
        unsigned int local:1;
+       unsigned int logout_on_delete:1;
+       unsigned int plogi_ack_needed:1;
+       unsigned int keep_nport_handle:1;
+
+       unsigned char logout_completed;
+
+       int generation;
 
        struct se_session *se_sess;
        struct scsi_qla_host *vha;
@@ -897,6 +924,10 @@ struct qla_tgt_sess {
 
        uint8_t port_name[WWN_SIZE];
        struct work_struct free_work;
+
+       union {
+               struct imm_ntfy_from_isp tm_iocb;
+       };
 };
 
 struct qla_tgt_cmd {
@@ -912,7 +943,6 @@ struct qla_tgt_cmd {
        unsigned int conf_compl_supported:1;
        unsigned int sg_mapped:1;
        unsigned int free_sg:1;
-       unsigned int aborted:1; /* Needed in case of SRR */
        unsigned int write_data_transferred:1;
        unsigned int ctx_dsd_alloced:1;
        unsigned int q_full:1;
@@ -961,6 +991,9 @@ struct qla_tgt_cmd {
         * BIT_14 - Back end data received/sent.
         * BIT_15 - SRR prepare ctio
         * BIT_16 - complete free
+        * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+        * BIT_18 - completion w/abort status
+        * BIT_19 - completion w/unknown status
         */
        uint32_t cmd_flags;
 };
@@ -1026,6 +1059,10 @@ struct qla_tgt_srr_ctio {
        struct qla_tgt_cmd *cmd;
 };
 
+/* Check for Switch reserved address */
+#define IS_SW_RESV_ADDR(_s_id) \
+       ((_s_id.b.domain == 0xff) && (_s_id.b.area == 0xfc))
+
 #define QLA_TGT_XMIT_DATA              1
 #define QLA_TGT_XMIT_STATUS            2
 #define QLA_TGT_XMIT_ALL               (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA)
@@ -1043,7 +1080,7 @@ extern int qlt_lport_register(void *, u64, u64, u64,
 extern void qlt_lport_deregister(struct scsi_qla_host *);
 extern void qlt_unreg_sess(struct qla_tgt_sess *);
 extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
-extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *);
+extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int);
 extern int __init qlt_init(void);
 extern void qlt_exit(void);
 extern void qlt_update_vp_map(struct scsi_qla_host *, int);
@@ -1073,12 +1110,23 @@ static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha)
                ha->host->active_mode |= MODE_INITIATOR;
 }
 
+static inline uint32_t sid_to_key(const uint8_t *s_id)
+{
+       uint32_t key;
+
+       key = (((unsigned long)s_id[0] << 16) |
+              ((unsigned long)s_id[1] << 8) |
+              (unsigned long)s_id[2]);
+       return key;
+}
+
 /*
  * Exported symbols from qla_target.c LLD logic used by qla2xxx code..
  */
 extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
 extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
 extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
+extern void qlt_abort_cmd(struct qla_tgt_cmd *);
 extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
@@ -1109,5 +1157,7 @@ extern void qlt_stop_phase2(struct qla_tgt *);
 extern irqreturn_t qla83xx_msix_atio_q(int, void *);
 extern void qlt_83xx_iospace_config(struct qla_hw_data *);
 extern int qlt_free_qfull_cmds(struct scsi_qla_host *);
+extern void qlt_logo_completion_handler(fc_port_t *, int);
+extern void qlt_do_generation_tick(struct scsi_qla_host *, int *);
 
 #endif /* __QLA_TARGET_H */
index d9a8c6084346759778c5cd8506c42d4ead19e2cc..9224a06646e6af420139ae29cba4802cf2663637 100644 (file)
@@ -374,7 +374,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
-
+       cmd->cmd_flags |= BIT_3;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
 
@@ -405,7 +405,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
            se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
                spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
                wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
-                                               3000);
+                                           3 * HZ);
                return 0;
        }
        spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -541,12 +541,10 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
        cmd->cmd_flags |= BIT_4;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
-       cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
 
        cmd->sg_cnt = se_cmd->t_data_nents;
        cmd->sg = se_cmd->t_data_sg;
        cmd->offset = 0;
-       cmd->cmd_flags |= BIT_3;
 
        cmd->prot_sg_cnt = se_cmd->t_prot_nents;
        cmd->prot_sg = se_cmd->t_prot_sg;
@@ -571,7 +569,6 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
        cmd->sg_cnt = 0;
        cmd->offset = 0;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
-       cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
        if (cmd->cmd_flags &  BIT_5) {
                pr_crit("Bit_5 already set for cmd = %p.\n", cmd);
                dump_stack();
@@ -636,14 +633,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
-       struct scsi_qla_host *vha = cmd->vha;
-       struct qla_hw_data *ha = vha->hw;
-
-       if (!cmd->sg_mapped)
-               return;
-
-       pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction);
-       cmd->sg_mapped = 0;
+       qlt_abort_cmd(cmd);
 }
 
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
@@ -1149,9 +1139,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
                return NULL;
        }
 
-       key = (((unsigned long)s_id[0] << 16) |
-              ((unsigned long)s_id[1] << 8) |
-              (unsigned long)s_id[2]);
+       key = sid_to_key(s_id);
        pr_debug("find_sess_by_s_id: 0x%06x\n", key);
 
        se_nacl = btree_lookup32(&lport->lport_fcport_map, key);
@@ -1186,9 +1174,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
        void *slot;
        int rc;
 
-       key = (((unsigned long)s_id[0] << 16) |
-              ((unsigned long)s_id[1] << 8) |
-              (unsigned long)s_id[2]);
+       key = sid_to_key(s_id);
        pr_debug("set_sess_by_s_id: %06x\n", key);
 
        slot = btree_lookup32(&lport->lport_fcport_map, key);
@@ -1544,6 +1530,10 @@ static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
        }
 
        sess->conf_compl_supported = conf_compl_supported;
+
+       /* Reset logout parameters to default */
+       sess->logout_on_delete = 1;
+       sess->keep_nport_handle = 0;
 }
 
 /*
index 106884a5444e1cb6f61057c29f813c4d713760fa..6457a8a0db9c37ed8892c28effe768a533f2e7f3 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
-#include <asm/unaligned.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -944,7 +943,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
                            scmd->sdb.length);
                scmd->sdb.table.sgl = &ses->sense_sgl;
                scmd->sc_data_direction = DMA_FROM_DEVICE;
-               scmd->sdb.table.nents = 1;
+               scmd->sdb.table.nents = scmd->sdb.table.orig_nents = 1;
                scmd->cmnd[0] = REQUEST_SENSE;
                scmd->cmnd[4] = scmd->sdb.length;
                scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
@@ -2523,33 +2522,3 @@ void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
        }
 }
 EXPORT_SYMBOL(scsi_build_sense_buffer);
-
-/**
- * scsi_set_sense_information - set the information field in a
- *             formatted sense data buffer
- * @buf:       Where to build sense data
- * @info:      64-bit information value to be set
- *
- **/
-void scsi_set_sense_information(u8 *buf, u64 info)
-{
-       if ((buf[0] & 0x7f) == 0x72) {
-               u8 *ucp, len;
-
-               len = buf[7];
-               ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
-               if (!ucp) {
-                       buf[7] = len + 0xa;
-                       ucp = buf + 8 + len;
-               }
-               ucp[0] = 0;
-               ucp[1] = 0xa;
-               ucp[2] = 0x80; /* Valid bit */
-               ucp[3] = 0;
-               put_unaligned_be64(info, &ucp[4]);
-       } else if ((buf[0] & 0x7f) == 0x70) {
-               buf[0] |= 0x80;
-               put_unaligned_be64(info, &buf[3]);
-       }
-}
-EXPORT_SYMBOL(scsi_set_sense_information);
index b1a263137a23391a1e19c2589f35fdaf2c4f514f..448ebdaa3d694758dd899b1c06ce379d0676898a 100644 (file)
@@ -583,7 +583,7 @@ static struct scatterlist *scsi_sg_alloc(unsigned int nents, gfp_t gfp_mask)
 
 static void scsi_free_sgtable(struct scsi_data_buffer *sdb, bool mq)
 {
-       if (mq && sdb->table.nents <= SCSI_MAX_SG_SEGMENTS)
+       if (mq && sdb->table.orig_nents <= SCSI_MAX_SG_SEGMENTS)
                return;
        __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, mq, scsi_sg_free);
 }
@@ -597,8 +597,8 @@ static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, bool mq)
 
        if (mq) {
                if (nents <= SCSI_MAX_SG_SEGMENTS) {
-                       sdb->table.nents = nents;
-                       sg_init_table(sdb->table.sgl, sdb->table.nents);
+                       sdb->table.nents = sdb->table.orig_nents = nents;
+                       sg_init_table(sdb->table.sgl, nents);
                        return 0;
                }
                first_chunk = sdb->table.sgl;
index 9e43ae1d2163dacaae769a816dc6973cfabbdca0..e4b7998379485454d26e39f6a5a91917a155ffbb 100644 (file)
@@ -217,15 +217,15 @@ static int sdev_runtime_suspend(struct device *dev)
 {
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        struct scsi_device *sdev = to_scsi_device(dev);
-       int err;
+       int err = 0;
 
-       err = blk_pre_runtime_suspend(sdev->request_queue);
-       if (err)
-               return err;
-       if (pm && pm->runtime_suspend)
+       if (pm && pm->runtime_suspend) {
+               err = blk_pre_runtime_suspend(sdev->request_queue);
+               if (err)
+                       return err;
                err = pm->runtime_suspend(dev);
-       blk_post_runtime_suspend(sdev->request_queue, err);
-
+               blk_post_runtime_suspend(sdev->request_queue, err);
+       }
        return err;
 }
 
@@ -248,11 +248,11 @@ static int sdev_runtime_resume(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int err = 0;
 
-       blk_pre_runtime_resume(sdev->request_queue);
-       if (pm && pm->runtime_resume)
+       if (pm && pm->runtime_resume) {
+               blk_pre_runtime_resume(sdev->request_queue);
                err = pm->runtime_resume(dev);
-       blk_post_runtime_resume(sdev->request_queue, err);
-
+               blk_post_runtime_resume(sdev->request_queue, err);
+       }
        return err;
 }
 
index 1ac38e73df7eec896cf2835fd8588a1db5278a46..9ad41168d26df1897814121766cd2e8fbd3a0243 100644 (file)
@@ -859,7 +859,7 @@ sdev_store_queue_depth(struct device *dev, struct device_attribute *attr,
 
        depth = simple_strtoul(buf, NULL, 0);
 
-       if (depth < 1 || depth > sht->can_queue)
+       if (depth < 1 || depth > sdev->host->can_queue)
                return -EINVAL;
 
        retval = sht->change_queue_depth(sdev, depth);
index a85292b1d09d090261f89f2f6eed018f6277abb9..e3cd3ece44121c7d8ee3806a40a42acf069f6958 100644 (file)
@@ -203,7 +203,7 @@ static ssize_t srp_show_tmo(char *buf, int tmo)
        return tmo >= 0 ? sprintf(buf, "%d\n", tmo) : sprintf(buf, "off\n");
 }
 
-static int srp_parse_tmo(int *tmo, const char *buf)
+int srp_parse_tmo(int *tmo, const char *buf)
 {
        int res = 0;
 
@@ -214,6 +214,7 @@ static int srp_parse_tmo(int *tmo, const char *buf)
 
        return res;
 }
+EXPORT_SYMBOL(srp_parse_tmo);
 
 static ssize_t show_reconnect_delay(struct device *dev,
                                    struct device_attribute *attr, char *buf)
index 3b2fcb4fada0491c4500b42555fdef542b4399d2..a20da8c25b4f960224fb4d772aafea38c57e1656 100644 (file)
@@ -2770,9 +2770,9 @@ static int sd_revalidate_disk(struct gendisk *disk)
        max_xfer = sdkp->max_xfer_blocks;
        max_xfer <<= ilog2(sdp->sector_size) - 9;
 
-       max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue),
-                               max_xfer);
-       blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer);
+       sdkp->disk->queue->limits.max_sectors =
+               min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer);
+
        set_capacity(disk, sdkp->capacity);
        sd_config_write_same(sdkp);
        kfree(buffer);
index 3f25b8fa921d69bff68ff6aab6e4c0b1f6ac65d7..871f3553987d6956c34c250928081feb10e3b9a0 100644 (file)
@@ -1329,9 +1329,9 @@ static int st_open(struct inode *inode, struct file *filp)
        spin_lock(&st_use_lock);
        STp->in_use = 0;
        spin_unlock(&st_use_lock);
-       scsi_tape_put(STp);
        if (resumed)
                scsi_autopm_put_device(STp->device);
+       scsi_tape_put(STp);
        return retval;
 
 }
index 285f77544c36391a89b243001c3fc93d0703f46f..7dbbb29d24c6cf5290cd06a7a97df570a8860f18 100644 (file)
@@ -949,7 +949,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
 {
        struct Scsi_Host *shost;
        struct virtio_scsi *vscsi;
-       int err, host_prot;
+       int err;
        u32 sg_elems, num_targets;
        u32 cmd_per_lun;
        u32 num_queues;
@@ -1009,6 +1009,8 @@ static int virtscsi_probe(struct virtio_device *vdev)
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
        if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) {
+               int host_prot;
+
                host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION |
                            SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION |
                            SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION;
index 0cae1694014dfbbaba171187fdbd4fc835dc1546..43f6d3dc0fa0bbb253a4ad5c8b028e73d4b02e1b 100644 (file)
@@ -326,6 +326,15 @@ config SPI_MESON_SPIFC
          This enables master mode support for the SPIFC (SPI flash
          controller) available in Amlogic Meson SoCs.
 
+config SPI_MT65XX
+       tristate "MediaTek SPI controller"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       help
+         This selects the MediaTek(R) SPI bus driver.
+         If you want to use MediaTek(R) SPI interface,
+         say Y or M here.If you are not sure, say N.
+         SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
+
 config SPI_OC_TINY
        tristate "OpenCores tiny SPI"
        depends on GPIOLIB || COMPILE_TEST
@@ -612,7 +621,7 @@ config SPI_XTENSA_XTFPGA
 
 config SPI_ZYNQMP_GQSPI
        tristate "Xilinx ZynqMP GQSPI controller"
-       depends on SPI_MASTER
+       depends on SPI_MASTER && HAS_DMA
        help
          Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
 
index 1154dbac8f2c184b165f7f4f9c2392a2820f6c97..9746beb21769458146ab723242d11f5aa64e9d8a 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_MESON_SPIFC)         += spi-meson-spifc.o
 obj-$(CONFIG_SPI_MPC512x_PSC)          += spi-mpc512x-psc.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += spi-mpc52xx-psc.o
 obj-$(CONFIG_SPI_MPC52xx)              += spi-mpc52xx.o
+obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
 obj-$(CONFIG_SPI_MXS)                  += spi-mxs.o
 obj-$(CONFIG_SPI_NUC900)               += spi-nuc900.o
 obj-$(CONFIG_SPI_OC_TINY)              += spi-oc-tiny.o
index c9eca347787db7ba5f85f6b1c4e10ad66e856abb..bf9ed380bb1c0754addbd27aedf7d874cee89ff2 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/interrupt.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
-#include <linux/platform_data/atmel.h>
 #include <linux/platform_data/dma-atmel.h>
 #include <linux/of.h>
 
index 59705ab23577494b68a136ca0f3c377b3371ca2b..e7874a6171ecdb4b5b5e7c99bb706aaca2135e2d 100644 (file)
@@ -480,7 +480,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
                                         struct spi_device *spi,
                                         struct spi_transfer *tfr,
                                         u32 cs,
-                                        unsigned long xfer_time_us)
+                                        unsigned long long xfer_time_us)
 {
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
        unsigned long timeout;
@@ -531,7 +531,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
 {
        struct bcm2835_spi *bs = spi_master_get_devdata(master);
        unsigned long spi_hz, clk_hz, cdiv;
-       unsigned long spi_used_hz, xfer_time_us;
+       unsigned long spi_used_hz;
+       unsigned long long xfer_time_us;
        u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
        /* set clock */
@@ -553,13 +554,11 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
        spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
        bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
 
-       /* handle all the modes */
+       /* handle all the 3-wire mode */
        if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
                cs |= BCM2835_SPI_CS_REN;
-       if (spi->mode & SPI_CPOL)
-               cs |= BCM2835_SPI_CS_CPOL;
-       if (spi->mode & SPI_CPHA)
-               cs |= BCM2835_SPI_CS_CPHA;
+       else
+               cs &= ~BCM2835_SPI_CS_REN;
 
        /* for gpio_cs set dummy CS so that no HW-CS get changed
         * we can not run this in bcm2835_spi_set_cs, as it does
@@ -575,9 +574,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
        bs->rx_len = tfr->len;
 
        /* calculate the estimated time in us the transfer runs */
-       xfer_time_us = tfr->len
+       xfer_time_us = (unsigned long long)tfr->len
                * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
-               * 1000000 / spi_used_hz;
+               * 1000000;
+       do_div(xfer_time_us, spi_used_hz);
 
        /* for short requests run polling*/
        if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US)
@@ -592,6 +592,25 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
        return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
 }
 
+static int bcm2835_spi_prepare_message(struct spi_master *master,
+                                      struct spi_message *msg)
+{
+       struct spi_device *spi = msg->spi;
+       struct bcm2835_spi *bs = spi_master_get_devdata(master);
+       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+       cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA);
+
+       if (spi->mode & SPI_CPOL)
+               cs |= BCM2835_SPI_CS_CPOL;
+       if (spi->mode & SPI_CPHA)
+               cs |= BCM2835_SPI_CS_CPHA;
+
+       bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+
+       return 0;
+}
+
 static void bcm2835_spi_handle_err(struct spi_master *master,
                                   struct spi_message *msg)
 {
@@ -739,6 +758,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        master->set_cs = bcm2835_spi_set_cs;
        master->transfer_one = bcm2835_spi_transfer_one;
        master->handle_err = bcm2835_spi_handle_err;
+       master->prepare_message = bcm2835_spi_prepare_message;
        master->dev.of_node = pdev->dev.of_node;
 
        bs = spi_master_get_devdata(master);
index f5ca6dc3a157879895aa0953c4c6681594b3d5ff..55789f7cda9280b2f0d21b65b6a7f3c019780047 100644 (file)
@@ -76,6 +76,7 @@
 #define HSSPI_FIFO_REG(x)                      (0x200 + (x) * 0x200)
 
 
+#define HSSPI_OP_MULTIBIT                      BIT(11)
 #define HSSPI_OP_CODE_SHIFT                    13
 #define HSSPI_OP_SLEEP                         (0 << HSSPI_OP_CODE_SHIFT)
 #define HSSPI_OP_READ_WRITE                    (1 << HSSPI_OP_CODE_SHIFT)
@@ -171,9 +172,12 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
        if (opcode != HSSPI_OP_READ)
                step_size -= HSSPI_OPCODE_LEN;
 
-       __raw_writel(0 << MODE_CTRL_PREPENDBYTE_CNT_SHIFT |
-                    2 << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT |
-                    2 << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT | 0xff,
+       if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
+           (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL))
+               opcode |= HSSPI_OP_MULTIBIT;
+
+       __raw_writel(1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT |
+                    1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT | 0xff,
                     bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
 
        while (pending > 0) {
@@ -374,7 +378,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
        master->num_chipselect = 8;
        master->setup = bcm63xx_hsspi_setup;
        master->transfer_one_message = bcm63xx_hsspi_transfer_one;
-       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+                           SPI_RX_DUAL | SPI_TX_DUAL;
        master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->auto_runtime_pm = true;
 
index 06b34e5bcfa37eaf9eba3e9ff8d1d017454dc81d..47bb9b898dfdc6ab18ae5fd10349f23882200e4f 100644 (file)
@@ -49,7 +49,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
 {
        /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
 
-       bool oldbit = !(word & 1);
+       u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
        /* clock starts at inactive polarity */
        for (word <<= (32 - bits); likely(bits); bits--) {
 
@@ -81,7 +81,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
 {
        /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
 
-       bool oldbit = !(word & (1 << 31));
+       u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
        /* clock starts at inactive polarity */
        for (word <<= (32 - bits); likely(bits); bits--) {
 
index 987afebea09379507f2c8505e7f4c14acbde079c..3cf9faa6cc3fe871174ec1b2777472b0ac4c6883 100644 (file)
@@ -139,6 +139,8 @@ struct davinci_spi {
        u32                     (*get_tx)(struct davinci_spi *);
 
        u8                      *bytes_per_word;
+
+       u8                      prescaler_limit;
 };
 
 static struct davinci_spi_config davinci_spi_default_cfg;
@@ -255,7 +257,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
  * This function calculates the prescale value that generates a clock rate
  * less than or equal to the specified maximum.
  *
- * Returns: calculated prescale - 1 for easy programming into SPI registers
+ * Returns: calculated prescale value for easy programming into SPI registers
  * or negative error number if valid prescalar cannot be updated.
  */
 static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
@@ -263,12 +265,13 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
 {
        int ret;
 
-       ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz);
+       /* Subtract 1 to match what will be programmed into SPI register. */
+       ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz) - 1;
 
-       if (ret < 1 || ret > 256)
+       if (ret < dspi->prescaler_limit || ret > 255)
                return -EINVAL;
 
-       return ret - 1;
+       return ret;
 }
 
 /**
@@ -832,13 +835,40 @@ rx_dma_failed:
 }
 
 #if defined(CONFIG_OF)
+
+/* OF SPI data structure */
+struct davinci_spi_of_data {
+       u8      version;
+       u8      prescaler_limit;
+};
+
+static const struct davinci_spi_of_data dm6441_spi_data = {
+       .version = SPI_VERSION_1,
+       .prescaler_limit = 2,
+};
+
+static const struct davinci_spi_of_data da830_spi_data = {
+       .version = SPI_VERSION_2,
+       .prescaler_limit = 2,
+};
+
+static const struct davinci_spi_of_data keystone_spi_data = {
+       .version = SPI_VERSION_1,
+       .prescaler_limit = 0,
+};
+
 static const struct of_device_id davinci_spi_of_match[] = {
        {
                .compatible = "ti,dm6441-spi",
+               .data = &dm6441_spi_data,
        },
        {
                .compatible = "ti,da830-spi",
-               .data = (void *)SPI_VERSION_2,
+               .data = &da830_spi_data,
+       },
+       {
+               .compatible = "ti,keystone-spi",
+               .data = &keystone_spi_data,
        },
        { },
 };
@@ -857,21 +887,21 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
                        struct davinci_spi *dspi)
 {
        struct device_node *node = pdev->dev.of_node;
+       struct davinci_spi_of_data *spi_data;
        struct davinci_spi_platform_data *pdata;
        unsigned int num_cs, intr_line = 0;
        const struct of_device_id *match;
 
        pdata = &dspi->pdata;
 
-       pdata->version = SPI_VERSION_1;
        match = of_match_device(davinci_spi_of_match, &pdev->dev);
        if (!match)
                return -ENODEV;
 
-       /* match data has the SPI version number for SPI_VERSION_2 */
-       if (match->data == (void *)SPI_VERSION_2)
-               pdata->version = SPI_VERSION_2;
+       spi_data = (struct davinci_spi_of_data *)match->data;
 
+       pdata->version = spi_data->version;
+       pdata->prescaler_limit = spi_data->prescaler_limit;
        /*
         * default num_cs is 1 and all chipsel are internal to the chip
         * indicated by chip_sel being NULL or cs_gpios being NULL or
@@ -991,7 +1021,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
 
        dspi->bitbang.chipselect = davinci_spi_chipselect;
        dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
-
+       dspi->prescaler_limit = pdata->prescaler_limit;
        dspi->version = pdata->version;
 
        dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
index eb03e1215195bd5f9e9ea882cb1895db6ea79cdd..7edede6e024ba493ce0dfc7038d83e03eb88ef85 100644 (file)
@@ -74,6 +74,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
 
        dws->max_freq = clk_get_rate(dwsmmio->clk);
 
+       of_property_read_u32(pdev->dev.of_node, "reg-io-width",
+                            &dws->reg_io_width);
+
        num_cs = 4;
 
        if (pdev->dev.of_node)
index 8d67d03c71ebcdec375023f8db910d3d0d8469ec..4fbfcdc5cb244d6e9f2a7edaba603b7ccd269fb0 100644 (file)
@@ -194,7 +194,7 @@ static void dw_writer(struct dw_spi *dws)
                        else
                                txw = *(u16 *)(dws->tx);
                }
-               dw_writel(dws, DW_SPI_DR, txw);
+               dw_write_io_reg(dws, DW_SPI_DR, txw);
                dws->tx += dws->n_bytes;
        }
 }
@@ -205,7 +205,7 @@ static void dw_reader(struct dw_spi *dws)
        u16 rxw;
 
        while (max--) {
-               rxw = dw_readl(dws, DW_SPI_DR);
+               rxw = dw_read_io_reg(dws, DW_SPI_DR);
                /* Care rx only if the transfer's original "rx" is not null */
                if (dws->rx_end - dws->len) {
                        if (dws->n_bytes == 1)
index 6c91391c1a4f8f07b40cb546de3eb169c44670f3..b75ed327d5a29832ad3461cb28da1089ade94cba 100644 (file)
@@ -109,6 +109,7 @@ struct dw_spi {
        u32                     fifo_len;       /* depth of the FIFO buffer */
        u32                     max_freq;       /* max bus freq supported */
 
+       u32                     reg_io_width;   /* DR I/O width in bytes */
        u16                     bus_num;
        u16                     num_cs;         /* supported slave numbers */
 
@@ -145,11 +146,45 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset)
        return __raw_readl(dws->regs + offset);
 }
 
+static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
+{
+       return __raw_readw(dws->regs + offset);
+}
+
 static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
 {
        __raw_writel(val, dws->regs + offset);
 }
 
+static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
+{
+       __raw_writew(val, dws->regs + offset);
+}
+
+static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset)
+{
+       switch (dws->reg_io_width) {
+       case 2:
+               return dw_readw(dws, offset);
+       case 4:
+       default:
+               return dw_readl(dws, offset);
+       }
+}
+
+static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
+{
+       switch (dws->reg_io_width) {
+       case 2:
+               dw_writew(dws, offset, val);
+               break;
+       case 4:
+       default:
+               dw_writel(dws, offset, val);
+               break;
+       }
+}
+
 static inline void spi_enable_chip(struct dw_spi *dws, int enable)
 {
        dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
index d3f05a0525a428194e0cb792604eed8ac481bd00..c27124a5ec8ee02264df2feaf283fdbb92991cf3 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/pm_runtime.h>
 #include <sysdev/fsl_soc.h>
 
 #include "spi-fsl-lib.h"
@@ -85,6 +86,8 @@ struct fsl_espi_transfer {
 #define SPCOM_TRANLEN(x)       ((x) << 0)
 #define        SPCOM_TRANLEN_MAX       0xFFFF  /* Max transaction length */
 
+#define AUTOSUSPEND_TIMEOUT 2000
+
 static void fsl_espi_change_mode(struct spi_device *spi)
 {
        struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
@@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi)
        mpc8xxx_spi = spi_master_get_devdata(spi->master);
        reg_base = mpc8xxx_spi->reg_base;
 
+       pm_runtime_get_sync(mpc8xxx_spi->dev);
+
        hw_mode = cs->hw_mode; /* Save original settings */
        cs->hw_mode = mpc8xxx_spi_read_reg(
                        &reg_base->csmode[spi->chip_select]);
@@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi)
        mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode);
 
        retval = fsl_espi_setup_transfer(spi, NULL);
+
+       pm_runtime_mark_last_busy(mpc8xxx_spi->dev);
+       pm_runtime_put_autosuspend(mpc8xxx_spi->dev);
+
        if (retval < 0) {
                cs->hw_mode = hw_mode; /* Restore settings */
                return retval;
@@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
        return ret;
 }
 
-static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
+#ifdef CONFIG_PM
+static int fsl_espi_runtime_suspend(struct device *dev)
 {
-       iounmap(mspi->reg_base);
-}
-
-static int fsl_espi_suspend(struct spi_master *master)
-{
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       struct fsl_espi_reg *reg_base;
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+       struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
        u32 regval;
 
-       mpc8xxx_spi = spi_master_get_devdata(master);
-       reg_base = mpc8xxx_spi->reg_base;
-
        regval = mpc8xxx_spi_read_reg(&reg_base->mode);
        regval &= ~SPMODE_ENABLE;
        mpc8xxx_spi_write_reg(&reg_base->mode, regval);
@@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master)
        return 0;
 }
 
-static int fsl_espi_resume(struct spi_master *master)
+static int fsl_espi_runtime_resume(struct device *dev)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       struct fsl_espi_reg *reg_base;
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+       struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
        u32 regval;
 
-       mpc8xxx_spi = spi_master_get_devdata(master);
-       reg_base = mpc8xxx_spi->reg_base;
-
        regval = mpc8xxx_spi_read_reg(&reg_base->mode);
        regval |= SPMODE_ENABLE;
        mpc8xxx_spi_write_reg(&reg_base->mode, regval);
 
        return 0;
 }
+#endif
 
 static struct spi_master * fsl_espi_probe(struct device *dev,
                struct resource *mem, unsigned int irq)
@@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
        master->setup = fsl_espi_setup;
        master->cleanup = fsl_espi_cleanup;
        master->transfer_one_message = fsl_espi_do_one_msg;
-       master->prepare_transfer_hardware = fsl_espi_resume;
-       master->unprepare_transfer_hardware = fsl_espi_suspend;
+       master->auto_runtime_pm = true;
 
        mpc8xxx_spi = spi_master_get_devdata(master);
-       mpc8xxx_spi->spi_remove = fsl_espi_remove;
 
-       mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
-       if (!mpc8xxx_spi->reg_base) {
-               ret = -ENOMEM;
+       mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(mpc8xxx_spi->reg_base)) {
+               ret = PTR_ERR(mpc8xxx_spi->reg_base);
                goto err_probe;
        }
 
        reg_base = mpc8xxx_spi->reg_base;
 
        /* Register for SPI Interrupt */
-       ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq,
+       ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq,
                          0, "fsl_espi", mpc8xxx_spi);
        if (ret)
-               goto free_irq;
+               goto err_probe;
 
        if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
                mpc8xxx_spi->rx_shift = 16;
@@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
 
        mpc8xxx_spi_write_reg(&reg_base->mode, regval);
 
-       ret = spi_register_master(master);
+       pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+
+       ret = devm_spi_register_master(dev, master);
        if (ret < 0)
-               goto unreg_master;
+               goto err_pm;
 
        dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq);
 
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
        return master;
 
-unreg_master:
-       free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-free_irq:
-       iounmap(mpc8xxx_spi->reg_base);
+err_pm:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
 err_probe:
        spi_master_put(master);
 err:
@@ -809,7 +818,9 @@ err:
 
 static int of_fsl_espi_remove(struct platform_device *dev)
 {
-       return mpc8xxx_spi_remove(&dev->dev);
+       pm_runtime_disable(&dev->dev);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev)
                return ret;
        }
 
-       return fsl_espi_suspend(master);
+       ret = pm_runtime_force_suspend(dev);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int of_fsl_espi_resume(struct device *dev)
@@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev)
        struct mpc8xxx_spi *mpc8xxx_spi;
        struct fsl_espi_reg *reg_base;
        u32 regval;
-       int i;
+       int i, ret;
 
        mpc8xxx_spi = spi_master_get_devdata(master);
        reg_base = mpc8xxx_spi->reg_base;
@@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev)
 
        mpc8xxx_spi_write_reg(&reg_base->mode, regval);
 
+       ret = pm_runtime_force_resume(dev);
+       if (ret < 0)
+               return ret;
+
        return spi_master_resume(master);
 }
 #endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops espi_pm = {
+       SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend,
+                          fsl_espi_runtime_resume, NULL)
        SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume)
 };
 
index cb35d2f0d0e63cf0d5dcf2d7aaddb22c54590c4a..1e43412cd9f88921519f4d981c7a3229afc4a248 100644 (file)
@@ -114,25 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
 }
 EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe);
 
-int mpc8xxx_spi_remove(struct device *dev)
-{
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       struct spi_master *master;
-
-       master = dev_get_drvdata(dev);
-       mpc8xxx_spi = spi_master_get_devdata(master);
-
-       spi_unregister_master(master);
-
-       free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-
-       if (mpc8xxx_spi->spi_remove)
-               mpc8xxx_spi->spi_remove(mpc8xxx_spi);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove);
-
 int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
 {
        struct device *dev = &ofdev->dev;
index 1326a392adcad162dd303617a03bf675d40a7a68..84f5dcb7a897d1388b0c08223c69ba661ca21017 100644 (file)
@@ -54,9 +54,6 @@ struct mpc8xxx_spi {
        void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
        u32(*get_tx) (struct mpc8xxx_spi *);
 
-       /* hooks for different controller driver */
-       void (*spi_remove) (struct mpc8xxx_spi *mspi);
-
        unsigned int count;
        unsigned int irq;
 
index 60c590790854242dde41e86135192ca2c1cbb4a9..8b290d9d7935044640da36688e82fd01e90bf114 100644 (file)
@@ -559,12 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
        return ret;
 }
 
-static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
-{
-       iounmap(mspi->reg_base);
-       fsl_spi_cpm_free(mspi);
-}
-
 static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
 {
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
@@ -631,7 +625,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
        master->transfer_one_message = fsl_spi_do_one_msg;
 
        mpc8xxx_spi = spi_master_get_devdata(master);
-       mpc8xxx_spi->spi_remove = fsl_spi_remove;
        mpc8xxx_spi->max_bits_per_word = 32;
        mpc8xxx_spi->type = fsl_spi_get_type(dev);
 
@@ -639,10 +632,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
        if (ret)
                goto err_cpm_init;
 
-       mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
-       if (mpc8xxx_spi->reg_base == NULL) {
-               ret = -ENOMEM;
-               goto err_ioremap;
+       mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(mpc8xxx_spi->reg_base)) {
+               ret = PTR_ERR(mpc8xxx_spi->reg_base);
+               goto err_probe;
        }
 
        if (mpc8xxx_spi->type == TYPE_GRLIB)
@@ -661,11 +654,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
                                        &mpc8xxx_spi->tx_shift, 8, 1);
 
        /* Register for SPI Interrupt */
-       ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
-                         0, "fsl_spi", mpc8xxx_spi);
+       ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_spi_irq,
+                              0, "fsl_spi", mpc8xxx_spi);
 
        if (ret != 0)
-               goto free_irq;
+               goto err_probe;
 
        reg_base = mpc8xxx_spi->reg_base;
 
@@ -686,20 +679,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
 
        mpc8xxx_spi_write_reg(&reg_base->mode, regval);
 
-       ret = spi_register_master(master);
+       ret = devm_spi_register_master(dev, master);
        if (ret < 0)
-               goto unreg_master;
+               goto err_probe;
 
        dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
                 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
 
        return master;
 
-unreg_master:
-       free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-free_irq:
-       iounmap(mpc8xxx_spi->reg_base);
-err_ioremap:
+err_probe:
        fsl_spi_cpm_free(mpc8xxx_spi);
 err_cpm_init:
        spi_master_put(master);
@@ -866,11 +855,8 @@ static int of_fsl_spi_remove(struct platform_device *ofdev)
 {
        struct spi_master *master = platform_get_drvdata(ofdev);
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
-       int ret;
 
-       ret = mpc8xxx_spi_remove(&ofdev->dev);
-       if (ret)
-               return ret;
+       fsl_spi_cpm_free(mpc8xxx_spi);
        if (mpc8xxx_spi->type == TYPE_FSL)
                of_fsl_spi_free_chipselects(&ofdev->dev);
        return 0;
@@ -916,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
 
 static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
 {
-       return mpc8xxx_spi_remove(&pdev->dev);
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+
+       fsl_spi_cpm_free(mpc8xxx_spi);
+
+       return 0;
 }
 
 MODULE_ALIAS("platform:mpc8xxx_spi");
index 788e2b176a4f7707051bcc325538e7d2a6d599f4..823cbc92d1e75447b1487158ac097e1de3d50470 100644 (file)
@@ -40,6 +40,7 @@
 #define SPFI_CONTROL_SOFT_RESET                        BIT(11)
 #define SPFI_CONTROL_SEND_DMA                  BIT(10)
 #define SPFI_CONTROL_GET_DMA                   BIT(9)
+#define SPFI_CONTROL_SE                        BIT(8)
 #define SPFI_CONTROL_TMODE_SHIFT               5
 #define SPFI_CONTROL_TMODE_MASK                        0x7
 #define SPFI_CONTROL_TMODE_SINGLE              0
@@ -104,6 +105,10 @@ struct img_spfi {
        bool rx_dma_busy;
 };
 
+struct img_spfi_device_data {
+       bool gpio_requested;
+};
+
 static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
 {
        return readl(spfi->regs + reg);
@@ -266,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master,
                cpu_relax();
        }
 
-       ret = spfi_wait_all_done(spfi);
-       if (ret < 0)
-               return ret;
-
        if (rx_bytes > 0 || tx_bytes > 0) {
                dev_err(spfi->dev, "PIO transfer timed out\n");
                return -ETIMEDOUT;
        }
 
+       ret = spfi_wait_all_done(spfi);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
@@ -439,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master,
 
 static int img_spfi_setup(struct spi_device *spi)
 {
-       int ret;
-
-       ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
-                              GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
-                              dev_name(&spi->dev));
-       if (ret)
-               dev_err(&spi->dev, "can't request chipselect gpio %d\n",
+       int ret = -EINVAL;
+       struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
+
+       if (!spfi_data) {
+               spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
+               if (!spfi_data)
+                       return -ENOMEM;
+               spfi_data->gpio_requested = false;
+               spi_set_ctldata(spi, spfi_data);
+       }
+       if (!spfi_data->gpio_requested) {
+               ret = gpio_request_one(spi->cs_gpio,
+                                      (spi->mode & SPI_CS_HIGH) ?
+                                      GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+                                      dev_name(&spi->dev));
+               if (ret)
+                       dev_err(&spi->dev, "can't request chipselect gpio %d\n",
                                spi->cs_gpio);
-
+               else
+                       spfi_data->gpio_requested = true;
+       } else {
+               if (gpio_is_valid(spi->cs_gpio)) {
+                       int mode = ((spi->mode & SPI_CS_HIGH) ?
+                                   GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
+
+                       ret = gpio_direction_output(spi->cs_gpio, mode);
+                       if (ret)
+                               dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
+                                       spi->cs_gpio, ret);
+               }
+       }
        return ret;
 }
 
 static void img_spfi_cleanup(struct spi_device *spi)
 {
-       gpio_free(spi->cs_gpio);
+       struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
+
+       if (spfi_data) {
+               if (spfi_data->gpio_requested)
+                       gpio_free(spi->cs_gpio);
+               kfree(spfi_data);
+               spi_set_ctldata(spi, NULL);
+       }
 }
 
 static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
@@ -491,6 +525,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
        else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
                 xfer->rx_nbits == SPI_NBITS_QUAD)
                val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
+       val |= SPFI_CONTROL_SE;
        spfi_writel(spfi, val, SPFI_CONTROL);
 }
 
@@ -546,6 +581,7 @@ static int img_spfi_probe(struct platform_device *pdev)
        struct img_spfi *spfi;
        struct resource *res;
        int ret;
+       u32 max_speed_hz;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
        if (!master)
@@ -610,6 +646,19 @@ static int img_spfi_probe(struct platform_device *pdev)
        master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
        master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
 
+       /*
+        * Maximum speed supported by spfi is limited to the lower value
+        * between 1/4 of the SPFI clock or to "spfi-max-frequency"
+        * defined in the device tree.
+        * If no value is defined in the device tree assume the maximum
+        * speed supported to be 1/4 of the SPFI clock.
+        */
+       if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency",
+                                 &max_speed_hz)) {
+               if (master->max_speed_hz > max_speed_hz)
+                       master->max_speed_hz = max_speed_hz;
+       }
+
        master->setup = img_spfi_setup;
        master->cleanup = img_spfi_cleanup;
        master->transfer_one = img_spfi_transfer_one;
index eb7d3a6fb14c0694b55e5286933256c5962043ce..f9deb84e4e551bdd9c42c8ac204c80c18f0f8579 100644 (file)
@@ -201,8 +201,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
 
-       if (spi_imx->dma_is_inited && (transfer->len > spi_imx->rx_wml)
-           && (transfer->len > spi_imx->tx_wml))
+       if (spi_imx->dma_is_inited
+           && transfer->len > spi_imx->rx_wml * sizeof(u32)
+           && transfer->len > spi_imx->tx_wml * sizeof(u32))
                return true;
        return false;
 }
index 965d2bdcfdcc710e4c8f0374fffe4e9570b117b7..1e75341689a622916bad62e4429d4ed4c5315fc2 100644 (file)
 #include <linux/gpio.h>
 #include <asm/mpc52xx_psc.h>
 
+enum {
+       TYPE_MPC5121,
+       TYPE_MPC5125,
+};
+
+/*
+ * This macro abstracts the differences in the PSC register layout between
+ * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc).
+ */
+#define psc_addr(mps, regname) ({                                      \
+       void *__ret = NULL;                                             \
+       switch (mps->type) {                                            \
+       case TYPE_MPC5121: {                                            \
+                       struct mpc52xx_psc __iomem *psc = mps->psc;     \
+                       __ret = &psc->regname;                          \
+               };                                                      \
+               break;                                                  \
+       case TYPE_MPC5125: {                                            \
+                       struct mpc5125_psc __iomem *psc = mps->psc;     \
+                       __ret = &psc->regname;                          \
+               };                                                      \
+               break;                                                  \
+       }                                                               \
+       __ret; })
+
 struct mpc512x_psc_spi {
        void (*cs_control)(struct spi_device *spi, bool on);
 
        /* driver internal data */
-       struct mpc52xx_psc __iomem *psc;
+       int type;
+       void __iomem *psc;
        struct mpc512x_psc_fifo __iomem *fifo;
        unsigned int irq;
        u8 bits_per_word;
@@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
 {
        struct mpc512x_psc_spi_cs *cs = spi->controller_state;
        struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
-       struct mpc52xx_psc __iomem *psc = mps->psc;
        u32 sicr;
        u32 ccr;
        int speed;
        u16 bclkdiv;
 
-       sicr = in_be32(&psc->sicr);
+       sicr = in_be32(psc_addr(mps, sicr));
 
        /* Set clock phase and polarity */
        if (spi->mode & SPI_CPHA)
@@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
                sicr |= 0x10000000;
        else
                sicr &= ~0x10000000;
-       out_be32(&psc->sicr, sicr);
+       out_be32(psc_addr(mps, sicr), sicr);
 
-       ccr = in_be32(&psc->ccr);
+       ccr = in_be32(psc_addr(mps, ccr));
        ccr &= 0xFF000000;
        speed = cs->speed_hz;
        if (!speed)
@@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
        bclkdiv = (mps->mclk_rate / speed) - 1;
 
        ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
-       out_be32(&psc->ccr, ccr);
+       out_be32(psc_addr(mps, ccr), ccr);
        mps->bits_per_word = cs->bits_per_word;
 
        if (mps->cs_control && gpio_is_valid(spi->cs_gpio))
@@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
 static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
 {
        struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
-       struct mpc52xx_psc __iomem *psc = mps->psc;
 
        dev_dbg(&master->dev, "%s()\n", __func__);
 
        /* Zero MR2 */
-       in_8(&psc->mode);
-       out_8(&psc->mode, 0x0);
+       in_8(psc_addr(mps, mr2));
+       out_8(psc_addr(mps, mr2), 0x0);
 
        /* enable transmitter/receiver */
-       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+       out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
 
        return 0;
 }
@@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
 static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
 {
        struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
-       struct mpc52xx_psc __iomem *psc = mps->psc;
        struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
 
        dev_dbg(&master->dev, "%s()\n", __func__);
 
        /* disable transmitter/receiver and fifo interrupt */
-       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+       out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
        out_be32(&fifo->tximr, 0);
 
        return 0;
@@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
 static int mpc512x_psc_spi_port_config(struct spi_master *master,
                                       struct mpc512x_psc_spi *mps)
 {
-       struct mpc52xx_psc __iomem *psc = mps->psc;
        struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
        u32 sicr;
        u32 ccr;
@@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
        u16 bclkdiv;
 
        /* Reset the PSC into a known state */
-       out_8(&psc->command, MPC52xx_PSC_RST_RX);
-       out_8(&psc->command, MPC52xx_PSC_RST_TX);
-       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+       out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX);
+       out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX);
+       out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
 
        /* Disable psc interrupts all useful interrupts are in fifo */
-       out_be16(&psc->isr_imr.imr, 0);
+       out_be16(psc_addr(mps, isr_imr.imr), 0);
 
        /* Disable fifo interrupts, will be enabled later */
        out_be32(&fifo->tximr, 0);
@@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
                0x00004000 |    /* MSTR = 1   -- SPI master */
                0x00000800;     /* UseEOF = 1 -- SS low until EOF */
 
-       out_be32(&psc->sicr, sicr);
+       out_be32(psc_addr(mps, sicr), sicr);
 
-       ccr = in_be32(&psc->ccr);
+       ccr = in_be32(psc_addr(mps, ccr));
        ccr &= 0xFF000000;
        speed = 1000000;        /* default 1MHz */
        bclkdiv = (mps->mclk_rate / speed) - 1;
        ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
-       out_be32(&psc->ccr, ccr);
+       out_be32(psc_addr(mps, ccr), ccr);
 
        /* Set 2ms DTL delay */
-       out_8(&psc->ctur, 0x00);
-       out_8(&psc->ctlr, 0x82);
+       out_8(psc_addr(mps, ctur), 0x00);
+       out_8(psc_addr(mps, ctlr), 0x82);
 
        /* we don't use the alarms */
        out_be32(&fifo->rxalarm, 0xfff);
@@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 
        dev_set_drvdata(dev, master);
        mps = spi_master_get_devdata(master);
+       mps->type = (int)of_device_get_match_data(dev);
        mps->irq = irq;
 
        if (pdata == NULL) {
@@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op)
 }
 
 static const struct of_device_id mpc512x_psc_spi_of_match[] = {
-       { .compatible = "fsl,mpc5121-psc-spi", },
+       { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 },
+       { .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 },
        {},
 };
 
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
new file mode 100644 (file)
index 0000000..5f6315c
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Leilk Liu <leilk.liu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/spi-mt65xx.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define SPI_CFG0_REG                      0x0000
+#define SPI_CFG1_REG                      0x0004
+#define SPI_TX_SRC_REG                    0x0008
+#define SPI_RX_DST_REG                    0x000c
+#define SPI_TX_DATA_REG                   0x0010
+#define SPI_RX_DATA_REG                   0x0014
+#define SPI_CMD_REG                       0x0018
+#define SPI_STATUS0_REG                   0x001c
+#define SPI_PAD_SEL_REG                   0x0024
+
+#define SPI_CFG0_SCK_HIGH_OFFSET          0
+#define SPI_CFG0_SCK_LOW_OFFSET           8
+#define SPI_CFG0_CS_HOLD_OFFSET           16
+#define SPI_CFG0_CS_SETUP_OFFSET          24
+
+#define SPI_CFG1_CS_IDLE_OFFSET           0
+#define SPI_CFG1_PACKET_LOOP_OFFSET       8
+#define SPI_CFG1_PACKET_LENGTH_OFFSET     16
+#define SPI_CFG1_GET_TICK_DLY_OFFSET      30
+
+#define SPI_CFG1_CS_IDLE_MASK             0xff
+#define SPI_CFG1_PACKET_LOOP_MASK         0xff00
+#define SPI_CFG1_PACKET_LENGTH_MASK       0x3ff0000
+
+#define SPI_CMD_ACT                  BIT(0)
+#define SPI_CMD_RESUME               BIT(1)
+#define SPI_CMD_RST                  BIT(2)
+#define SPI_CMD_PAUSE_EN             BIT(4)
+#define SPI_CMD_DEASSERT             BIT(5)
+#define SPI_CMD_CPHA                 BIT(8)
+#define SPI_CMD_CPOL                 BIT(9)
+#define SPI_CMD_RX_DMA               BIT(10)
+#define SPI_CMD_TX_DMA               BIT(11)
+#define SPI_CMD_TXMSBF               BIT(12)
+#define SPI_CMD_RXMSBF               BIT(13)
+#define SPI_CMD_RX_ENDIAN            BIT(14)
+#define SPI_CMD_TX_ENDIAN            BIT(15)
+#define SPI_CMD_FINISH_IE            BIT(16)
+#define SPI_CMD_PAUSE_IE             BIT(17)
+
+#define MT8173_SPI_MAX_PAD_SEL 3
+
+#define MTK_SPI_PAUSE_INT_STATUS 0x2
+
+#define MTK_SPI_IDLE 0
+#define MTK_SPI_PAUSED 1
+
+#define MTK_SPI_MAX_FIFO_SIZE 32
+#define MTK_SPI_PACKET_SIZE 1024
+
+struct mtk_spi_compatible {
+       bool need_pad_sel;
+       /* Must explicitly send dummy Tx bytes to do Rx only transfer */
+       bool must_tx;
+};
+
+struct mtk_spi {
+       void __iomem *base;
+       u32 state;
+       u32 pad_sel;
+       struct clk *spi_clk, *parent_clk;
+       struct spi_transfer *cur_transfer;
+       u32 xfer_len;
+       struct scatterlist *tx_sgl, *rx_sgl;
+       u32 tx_sgl_len, rx_sgl_len;
+       const struct mtk_spi_compatible *dev_comp;
+};
+
+static const struct mtk_spi_compatible mt6589_compat;
+static const struct mtk_spi_compatible mt8135_compat;
+static const struct mtk_spi_compatible mt8173_compat = {
+       .need_pad_sel = true,
+       .must_tx = true,
+};
+
+/*
+ * A piece of default chip info unless the platform
+ * supplies it.
+ */
+static const struct mtk_chip_config mtk_default_chip_info = {
+       .rx_mlsb = 1,
+       .tx_mlsb = 1,
+};
+
+static const struct of_device_id mtk_spi_of_match[] = {
+       { .compatible = "mediatek,mt6589-spi", .data = (void *)&mt6589_compat },
+       { .compatible = "mediatek,mt8135-spi", .data = (void *)&mt8135_compat },
+       { .compatible = "mediatek,mt8173-spi", .data = (void *)&mt8173_compat },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
+
+static void mtk_spi_reset(struct mtk_spi *mdata)
+{
+       u32 reg_val;
+
+       /* set the software reset bit in SPI_CMD_REG. */
+       reg_val = readl(mdata->base + SPI_CMD_REG);
+       reg_val |= SPI_CMD_RST;
+       writel(reg_val, mdata->base + SPI_CMD_REG);
+
+       reg_val = readl(mdata->base + SPI_CMD_REG);
+       reg_val &= ~SPI_CMD_RST;
+       writel(reg_val, mdata->base + SPI_CMD_REG);
+}
+
+static void mtk_spi_config(struct mtk_spi *mdata,
+                          struct mtk_chip_config *chip_config)
+{
+       u32 reg_val;
+
+       reg_val = readl(mdata->base + SPI_CMD_REG);
+
+       /* set the mlsbx and mlsbtx */
+       if (chip_config->tx_mlsb)
+               reg_val |= SPI_CMD_TXMSBF;
+       else
+               reg_val &= ~SPI_CMD_TXMSBF;
+       if (chip_config->rx_mlsb)
+               reg_val |= SPI_CMD_RXMSBF;
+       else
+               reg_val &= ~SPI_CMD_RXMSBF;
+
+       /* set the tx/rx endian */
+#ifdef __LITTLE_ENDIAN
+       reg_val &= ~SPI_CMD_TX_ENDIAN;
+       reg_val &= ~SPI_CMD_RX_ENDIAN;
+#else
+       reg_val |= SPI_CMD_TX_ENDIAN;
+       reg_val |= SPI_CMD_RX_ENDIAN;
+#endif
+
+       /* set finish and pause interrupt always enable */
+       reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE;
+
+       /* disable dma mode */
+       reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA);
+
+       /* disable deassert mode */
+       reg_val &= ~SPI_CMD_DEASSERT;
+
+       writel(reg_val, mdata->base + SPI_CMD_REG);
+
+       /* pad select */
+       if (mdata->dev_comp->need_pad_sel)
+               writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG);
+}
+
+static int mtk_spi_prepare_hardware(struct spi_master *master)
+{
+       struct spi_transfer *trans;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+       struct spi_message *msg = master->cur_msg;
+
+       trans = list_first_entry(&msg->transfers, struct spi_transfer,
+                                transfer_list);
+       if (!trans->cs_change) {
+               mdata->state = MTK_SPI_IDLE;
+               mtk_spi_reset(mdata);
+       }
+
+       return 0;
+}
+
+static int mtk_spi_prepare_message(struct spi_master *master,
+                                  struct spi_message *msg)
+{
+       u32 reg_val;
+       u8 cpha, cpol;
+       struct mtk_chip_config *chip_config;
+       struct spi_device *spi = msg->spi;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       cpha = spi->mode & SPI_CPHA ? 1 : 0;
+       cpol = spi->mode & SPI_CPOL ? 1 : 0;
+
+       reg_val = readl(mdata->base + SPI_CMD_REG);
+       if (cpha)
+               reg_val |= SPI_CMD_CPHA;
+       else
+               reg_val &= ~SPI_CMD_CPHA;
+       if (cpol)
+               reg_val |= SPI_CMD_CPOL;
+       else
+               reg_val &= ~SPI_CMD_CPOL;
+       writel(reg_val, mdata->base + SPI_CMD_REG);
+
+       chip_config = spi->controller_data;
+       if (!chip_config) {
+               chip_config = (void *)&mtk_default_chip_info;
+               spi->controller_data = chip_config;
+       }
+       mtk_spi_config(mdata, chip_config);
+
+       return 0;
+}
+
+static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       u32 reg_val;
+       struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+
+       reg_val = readl(mdata->base + SPI_CMD_REG);
+       if (!enable)
+               reg_val |= SPI_CMD_PAUSE_EN;
+       else
+               reg_val &= ~SPI_CMD_PAUSE_EN;
+       writel(reg_val, mdata->base + SPI_CMD_REG);
+}
+
+static void mtk_spi_prepare_transfer(struct spi_master *master,
+                                    struct spi_transfer *xfer)
+{
+       u32 spi_clk_hz, div, sck_time, cs_time, reg_val = 0;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       spi_clk_hz = clk_get_rate(mdata->spi_clk);
+       if (xfer->speed_hz < spi_clk_hz / 2)
+               div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz);
+       else
+               div = 1;
+
+       sck_time = (div + 1) / 2;
+       cs_time = sck_time * 2;
+
+       reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET);
+       reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
+       reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
+       reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
+       writel(reg_val, mdata->base + SPI_CFG0_REG);
+
+       reg_val = readl(mdata->base + SPI_CFG1_REG);
+       reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
+       reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
+       writel(reg_val, mdata->base + SPI_CFG1_REG);
+}
+
+static void mtk_spi_setup_packet(struct spi_master *master)
+{
+       u32 packet_size, packet_loop, reg_val;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       packet_size = min_t(u32, mdata->xfer_len, MTK_SPI_PACKET_SIZE);
+       packet_loop = mdata->xfer_len / packet_size;
+
+       reg_val = readl(mdata->base + SPI_CFG1_REG);
+       reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK);
+       reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
+       reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
+       writel(reg_val, mdata->base + SPI_CFG1_REG);
+}
+
+static void mtk_spi_enable_transfer(struct spi_master *master)
+{
+       u32 cmd;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       cmd = readl(mdata->base + SPI_CMD_REG);
+       if (mdata->state == MTK_SPI_IDLE)
+               cmd |= SPI_CMD_ACT;
+       else
+               cmd |= SPI_CMD_RESUME;
+       writel(cmd, mdata->base + SPI_CMD_REG);
+}
+
+static int mtk_spi_get_mult_delta(u32 xfer_len)
+{
+       u32 mult_delta;
+
+       if (xfer_len > MTK_SPI_PACKET_SIZE)
+               mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
+       else
+               mult_delta = 0;
+
+       return mult_delta;
+}
+
+static void mtk_spi_update_mdata_len(struct spi_master *master)
+{
+       int mult_delta;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       if (mdata->tx_sgl_len && mdata->rx_sgl_len) {
+               if (mdata->tx_sgl_len > mdata->rx_sgl_len) {
+                       mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
+                       mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
+                       mdata->rx_sgl_len = mult_delta;
+                       mdata->tx_sgl_len -= mdata->xfer_len;
+               } else {
+                       mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
+                       mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
+                       mdata->tx_sgl_len = mult_delta;
+                       mdata->rx_sgl_len -= mdata->xfer_len;
+               }
+       } else if (mdata->tx_sgl_len) {
+               mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len);
+               mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
+               mdata->tx_sgl_len = mult_delta;
+       } else if (mdata->rx_sgl_len) {
+               mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len);
+               mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
+               mdata->rx_sgl_len = mult_delta;
+       }
+}
+
+static void mtk_spi_setup_dma_addr(struct spi_master *master,
+                                  struct spi_transfer *xfer)
+{
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       if (mdata->tx_sgl)
+               writel(xfer->tx_dma, mdata->base + SPI_TX_SRC_REG);
+       if (mdata->rx_sgl)
+               writel(xfer->rx_dma, mdata->base + SPI_RX_DST_REG);
+}
+
+static int mtk_spi_fifo_transfer(struct spi_master *master,
+                                struct spi_device *spi,
+                                struct spi_transfer *xfer)
+{
+       int cnt;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       mdata->cur_transfer = xfer;
+       mdata->xfer_len = xfer->len;
+       mtk_spi_prepare_transfer(master, xfer);
+       mtk_spi_setup_packet(master);
+
+       if (xfer->len % 4)
+               cnt = xfer->len / 4 + 1;
+       else
+               cnt = xfer->len / 4;
+       iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt);
+
+       mtk_spi_enable_transfer(master);
+
+       return 1;
+}
+
+static int mtk_spi_dma_transfer(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
+{
+       int cmd;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       mdata->tx_sgl = NULL;
+       mdata->rx_sgl = NULL;
+       mdata->tx_sgl_len = 0;
+       mdata->rx_sgl_len = 0;
+       mdata->cur_transfer = xfer;
+
+       mtk_spi_prepare_transfer(master, xfer);
+
+       cmd = readl(mdata->base + SPI_CMD_REG);
+       if (xfer->tx_buf)
+               cmd |= SPI_CMD_TX_DMA;
+       if (xfer->rx_buf)
+               cmd |= SPI_CMD_RX_DMA;
+       writel(cmd, mdata->base + SPI_CMD_REG);
+
+       if (xfer->tx_buf)
+               mdata->tx_sgl = xfer->tx_sg.sgl;
+       if (xfer->rx_buf)
+               mdata->rx_sgl = xfer->rx_sg.sgl;
+
+       if (mdata->tx_sgl) {
+               xfer->tx_dma = sg_dma_address(mdata->tx_sgl);
+               mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
+       }
+       if (mdata->rx_sgl) {
+               xfer->rx_dma = sg_dma_address(mdata->rx_sgl);
+               mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
+       }
+
+       mtk_spi_update_mdata_len(master);
+       mtk_spi_setup_packet(master);
+       mtk_spi_setup_dma_addr(master, xfer);
+       mtk_spi_enable_transfer(master);
+
+       return 1;
+}
+
+static int mtk_spi_transfer_one(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
+{
+       if (master->can_dma(master, spi, xfer))
+               return mtk_spi_dma_transfer(master, spi, xfer);
+       else
+               return mtk_spi_fifo_transfer(master, spi, xfer);
+}
+
+static bool mtk_spi_can_dma(struct spi_master *master,
+                           struct spi_device *spi,
+                           struct spi_transfer *xfer)
+{
+       return xfer->len > MTK_SPI_MAX_FIFO_SIZE;
+}
+
+static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+{
+       u32 cmd, reg_val, cnt;
+       struct spi_master *master = dev_id;
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+       struct spi_transfer *trans = mdata->cur_transfer;
+
+       reg_val = readl(mdata->base + SPI_STATUS0_REG);
+       if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
+               mdata->state = MTK_SPI_PAUSED;
+       else
+               mdata->state = MTK_SPI_IDLE;
+
+       if (!master->can_dma(master, master->cur_msg->spi, trans)) {
+               if (trans->rx_buf) {
+                       if (mdata->xfer_len % 4)
+                               cnt = mdata->xfer_len / 4 + 1;
+                       else
+                               cnt = mdata->xfer_len / 4;
+                       ioread32_rep(mdata->base + SPI_RX_DATA_REG,
+                                    trans->rx_buf, cnt);
+               }
+               spi_finalize_current_transfer(master);
+               return IRQ_HANDLED;
+       }
+
+       if (mdata->tx_sgl)
+               trans->tx_dma += mdata->xfer_len;
+       if (mdata->rx_sgl)
+               trans->rx_dma += mdata->xfer_len;
+
+       if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) {
+               mdata->tx_sgl = sg_next(mdata->tx_sgl);
+               if (mdata->tx_sgl) {
+                       trans->tx_dma = sg_dma_address(mdata->tx_sgl);
+                       mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
+               }
+       }
+       if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) {
+               mdata->rx_sgl = sg_next(mdata->rx_sgl);
+               if (mdata->rx_sgl) {
+                       trans->rx_dma = sg_dma_address(mdata->rx_sgl);
+                       mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
+               }
+       }
+
+       if (!mdata->tx_sgl && !mdata->rx_sgl) {
+               /* spi disable dma */
+               cmd = readl(mdata->base + SPI_CMD_REG);
+               cmd &= ~SPI_CMD_TX_DMA;
+               cmd &= ~SPI_CMD_RX_DMA;
+               writel(cmd, mdata->base + SPI_CMD_REG);
+
+               spi_finalize_current_transfer(master);
+               return IRQ_HANDLED;
+       }
+
+       mtk_spi_update_mdata_len(master);
+       mtk_spi_setup_packet(master);
+       mtk_spi_setup_dma_addr(master, trans);
+       mtk_spi_enable_transfer(master);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct mtk_spi *mdata;
+       const struct of_device_id *of_id;
+       struct resource *res;
+       int irq, ret;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
+       if (!master) {
+               dev_err(&pdev->dev, "failed to alloc spi master\n");
+               return -ENOMEM;
+       }
+
+       master->auto_runtime_pm = true;
+       master->dev.of_node = pdev->dev.of_node;
+       master->mode_bits = SPI_CPOL | SPI_CPHA;
+
+       master->set_cs = mtk_spi_set_cs;
+       master->prepare_transfer_hardware = mtk_spi_prepare_hardware;
+       master->prepare_message = mtk_spi_prepare_message;
+       master->transfer_one = mtk_spi_transfer_one;
+       master->can_dma = mtk_spi_can_dma;
+
+       of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
+       if (!of_id) {
+               dev_err(&pdev->dev, "failed to probe of_node\n");
+               ret = -EINVAL;
+               goto err_put_master;
+       }
+
+       mdata = spi_master_get_devdata(master);
+       mdata->dev_comp = of_id->data;
+       if (mdata->dev_comp->must_tx)
+               master->flags = SPI_MASTER_MUST_TX;
+
+       if (mdata->dev_comp->need_pad_sel) {
+               ret = of_property_read_u32(pdev->dev.of_node,
+                                          "mediatek,pad-select",
+                                          &mdata->pad_sel);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to read pad select: %d\n",
+                               ret);
+                       goto err_put_master;
+               }
+
+               if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) {
+                       dev_err(&pdev->dev, "wrong pad-select: %u\n",
+                               mdata->pad_sel);
+                       ret = -EINVAL;
+                       goto err_put_master;
+               }
+       }
+
+       platform_set_drvdata(pdev, master);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               dev_err(&pdev->dev, "failed to determine base address\n");
+               goto err_put_master;
+       }
+
+       mdata->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mdata->base)) {
+               ret = PTR_ERR(mdata->base);
+               goto err_put_master;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get irq (%d)\n", irq);
+               ret = irq;
+               goto err_put_master;
+       }
+
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+       ret = devm_request_irq(&pdev->dev, irq, mtk_spi_interrupt,
+                              IRQF_TRIGGER_NONE, dev_name(&pdev->dev), master);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register irq (%d)\n", ret);
+               goto err_put_master;
+       }
+
+       mdata->spi_clk = devm_clk_get(&pdev->dev, "spi-clk");
+       if (IS_ERR(mdata->spi_clk)) {
+               ret = PTR_ERR(mdata->spi_clk);
+               dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret);
+               goto err_put_master;
+       }
+
+       mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk");
+       if (IS_ERR(mdata->parent_clk)) {
+               ret = PTR_ERR(mdata->parent_clk);
+               dev_err(&pdev->dev, "failed to get parent-clk: %d\n", ret);
+               goto err_put_master;
+       }
+
+       ret = clk_prepare_enable(mdata->spi_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret);
+               goto err_put_master;
+       }
+
+       ret = clk_set_parent(mdata->spi_clk, mdata->parent_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret);
+               goto err_disable_clk;
+       }
+
+       clk_disable_unprepare(mdata->spi_clk);
+
+       pm_runtime_enable(&pdev->dev);
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register master (%d)\n", ret);
+               goto err_put_master;
+       }
+
+       return 0;
+
+err_disable_clk:
+       clk_disable_unprepare(mdata->spi_clk);
+err_put_master:
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int mtk_spi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       pm_runtime_disable(&pdev->dev);
+
+       mtk_spi_reset(mdata);
+       clk_disable_unprepare(mdata->spi_clk);
+       spi_master_put(master);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_spi_suspend(struct device *dev)
+{
+       int ret;
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       ret = spi_master_suspend(master);
+       if (ret)
+               return ret;
+
+       if (!pm_runtime_suspended(dev))
+               clk_disable_unprepare(mdata->spi_clk);
+
+       return ret;
+}
+
+static int mtk_spi_resume(struct device *dev)
+{
+       int ret;
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       if (!pm_runtime_suspended(dev)) {
+               ret = clk_prepare_enable(mdata->spi_clk);
+               if (ret < 0) {
+                       dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = spi_master_resume(master);
+       if (ret < 0)
+               clk_disable_unprepare(mdata->spi_clk);
+
+       return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int mtk_spi_runtime_suspend(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+
+       clk_disable_unprepare(mdata->spi_clk);
+
+       return 0;
+}
+
+static int mtk_spi_runtime_resume(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mtk_spi *mdata = spi_master_get_devdata(master);
+       int ret;
+
+       ret = clk_prepare_enable(mdata->spi_clk);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mtk_spi_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume)
+       SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend,
+                          mtk_spi_runtime_resume, NULL)
+};
+
+static struct platform_driver mtk_spi_driver = {
+       .driver = {
+               .name = "mtk-spi",
+               .pm     = &mtk_spi_pm,
+               .of_match_table = mtk_spi_of_match,
+       },
+       .probe = mtk_spi_probe,
+       .remove = mtk_spi_remove,
+};
+
+module_platform_driver(mtk_spi_driver);
+
+MODULE_DESCRIPTION("MTK SPI Controller driver");
+MODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mtk-spi");
index 58673841286c335adc123d5200c1a0f128ecab04..3d09e0b69b73241c58d50e788dbdaf5cd16bf7ea 100644 (file)
@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
 
 static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
 {
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
        u32 l;
 
        /* The controller handles the inverted chip selects
@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
                enable = !enable;
 
        if (spi->controller_state) {
+               int err = pm_runtime_get_sync(mcspi->dev);
+               if (err < 0) {
+                       dev_err(mcspi->dev, "failed to get sync: %d\n", err);
+                       return;
+               }
+
                l = mcspi_cached_chconf0(spi);
 
                if (enable)
@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
                        l |= OMAP2_MCSPI_CHCONF_FORCE;
 
                mcspi_write_chconf0(spi, l);
+
+               pm_runtime_mark_last_busy(mcspi->dev);
+               pm_runtime_put_autosuspend(mcspi->dev);
        }
 }
 
index 8cad107a5b3f7e6d3b77f79fbf56f4b49f944267..a87cfd4ba17b38f47a8e6c823c335c308c482dc8 100644 (file)
 #define ORION_SPI_DATA_OUT_REG         0x08
 #define ORION_SPI_DATA_IN_REG          0x0c
 #define ORION_SPI_INT_CAUSE_REG                0x10
+#define ORION_SPI_TIMING_PARAMS_REG    0x18
+
+#define ORION_SPI_TMISO_SAMPLE_MASK    (0x3 << 6)
+#define ORION_SPI_TMISO_SAMPLE_1       (1 << 6)
+#define ORION_SPI_TMISO_SAMPLE_2       (2 << 6)
 
 #define ORION_SPI_MODE_CPOL            (1 << 11)
 #define ORION_SPI_MODE_CPHA            (1 << 12)
@@ -70,6 +75,7 @@ struct orion_spi_dev {
        unsigned int            min_divisor;
        unsigned int            max_divisor;
        u32                     prescale_mask;
+       bool                    is_errata_50mhz_ac;
 };
 
 struct orion_spi {
@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi)
        writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
 }
 
+static void
+orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
+{
+       u32 reg;
+       struct orion_spi *orion_spi;
+
+       orion_spi = spi_master_get_devdata(spi->master);
+
+       /*
+        * Erratum description: (Erratum NO. FE-9144572) The device
+        * SPI interface supports frequencies of up to 50 MHz.
+        * However, due to this erratum, when the device core clock is
+        * 250 MHz and the SPI interfaces is configured for 50MHz SPI
+        * clock and CPOL=CPHA=1 there might occur data corruption on
+        * reads from the SPI device.
+        * Erratum Workaround:
+        * Work in one of the following configurations:
+        * 1. Set CPOL=CPHA=0 in "SPI Interface Configuration
+        * Register".
+        * 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1
+        * Register" before setting the interface.
+        */
+       reg = readl(spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
+       reg &= ~ORION_SPI_TMISO_SAMPLE_MASK;
+
+       if (clk_get_rate(orion_spi->clk) == 250000000 &&
+                       speed == 50000000 && spi->mode & SPI_CPOL &&
+                       spi->mode & SPI_CPHA)
+               reg |= ORION_SPI_TMISO_SAMPLE_2;
+       else
+               reg |= ORION_SPI_TMISO_SAMPLE_1; /* This is the default value */
+
+       writel(reg, spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
+}
+
 /*
  * called only when no transfer is active on the bus
  */
@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 
        orion_spi_mode_set(spi);
 
+       if (orion_spi->devdata->is_errata_50mhz_ac)
+               orion_spi_50mhz_ac_timing_erratum(spi, speed);
+
        rc = orion_spi_baudrate_set(spi, speed);
        if (rc)
                return rc;
@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = {
        .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
 };
 
+static const struct orion_spi_dev armada_380_spi_dev_data = {
+       .typ = ARMADA_SPI,
+       .max_hz = 50000000,
+       .max_divisor = 1920,
+       .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
+       .is_errata_50mhz_ac = true,
+};
+
 static const struct of_device_id orion_spi_of_match_table[] = {
        {
                .compatible = "marvell,orion-spi",
@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = {
        },
        {
                .compatible = "marvell,armada-380-spi",
-               .data = &armada_xp_spi_dev_data,
+               .data = &armada_380_spi_dev_data,
        },
        {
                .compatible = "marvell,armada-390-spi",
index 3cfd4357489aba1a5904da3f39d0d12346d2a908..d19d7f28aecb3c5ac9ca6409fc9c8e2e5f7fc180 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/of_device.h>
 #include <linux/module.h>
 #include <linux/spi/pxa2xx_spi.h>
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 
 #include <linux/dmaengine.h>
index 7293d6d875c5c692184d1c45aea151f063bb6cd0..fdd7919770419bcbf63afaf326e719e43ae6513b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/spi/spi.h>
@@ -97,6 +98,15 @@ static const struct lpss_config lpss_platforms[] = {
                .tx_threshold_lo = 160,
                .tx_threshold_hi = 224,
        },
+       {       /* LPSS_SPT_SSP */
+               .offset = 0x200,
+               .reg_general = -1,
+               .reg_ssp = 0x20,
+               .reg_cs_ctrl = 0x24,
+               .rx_threshold = 1,
+               .tx_threshold_lo = 32,
+               .tx_threshold_hi = 56,
+       },
 };
 
 static inline const struct lpss_config
@@ -110,6 +120,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
        switch (drv_data->ssp_type) {
        case LPSS_LPT_SSP:
        case LPSS_BYT_SSP:
+       case LPSS_SPT_SSP:
                return true;
        default:
                return false;
@@ -1107,6 +1118,7 @@ static int setup(struct spi_device *spi)
                break;
        case LPSS_LPT_SSP:
        case LPSS_BYT_SSP:
+       case LPSS_SPT_SSP:
                config = lpss_get_config(drv_data);
                tx_thres = config->tx_threshold_lo;
                tx_hi_thres = config->tx_threshold_hi;
@@ -1276,6 +1288,31 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
 
+/*
+ * PCI IDs of compound devices that integrate both host controller and private
+ * integrated DMA engine. Please note these are not used in module
+ * autoloading and probing in this module but matching the LPSS SSP type.
+ */
+static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
+       /* SPT-LP */
+       { PCI_VDEVICE(INTEL, 0x9d29), LPSS_SPT_SSP },
+       { PCI_VDEVICE(INTEL, 0x9d2a), LPSS_SPT_SSP },
+       /* SPT-H */
+       { PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
+       { PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
+       { },
+};
+
+static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
+{
+       struct device *dev = param;
+
+       if (dev != chan->device->dev->parent)
+               return false;
+
+       return true;
+}
+
 static struct pxa2xx_spi_master *
 pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 {
@@ -1283,16 +1320,25 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
        struct acpi_device *adev;
        struct ssp_device *ssp;
        struct resource *res;
-       const struct acpi_device_id *id;
+       const struct acpi_device_id *adev_id = NULL;
+       const struct pci_device_id *pcidev_id = NULL;
        int devid, type;
 
        if (!ACPI_HANDLE(&pdev->dev) ||
            acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
                return NULL;
 
-       id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
-       if (id)
-               type = (int)id->driver_data;
+       if (dev_is_pci(pdev->dev.parent))
+               pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
+                                        to_pci_dev(pdev->dev.parent));
+       else
+               adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
+                                           &pdev->dev);
+
+       if (adev_id)
+               type = (int)adev_id->driver_data;
+       else if (pcidev_id)
+               type = (int)pcidev_id->driver_data;
        else
                return NULL;
 
@@ -1311,6 +1357,12 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
        if (IS_ERR(ssp->mmio_base))
                return NULL;
 
+       if (pcidev_id) {
+               pdata->tx_param = pdev->dev.parent;
+               pdata->rx_param = pdev->dev.parent;
+               pdata->dma_filter = pxa2xx_spi_idma_filter;
+       }
+
        ssp->clk = devm_clk_get(&pdev->dev, NULL);
        ssp->irq = platform_get_irq(pdev, 0);
        ssp->type = type;
@@ -1362,8 +1414,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       /* Allocate master with space for drv_data and null dma buffer */
-       master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+       master = spi_alloc_master(dev, sizeof(struct driver_data));
        if (!master) {
                dev_err(&pdev->dev, "cannot alloc spi_master\n");
                pxa_ssp_free(ssp);
@@ -1390,7 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        master->auto_runtime_pm = true;
 
        drv_data->ssp_type = ssp->type;
-       drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
 
        drv_data->ioaddr = ssp->mmio_base;
        drv_data->ssdr_physical = ssp->phys_base + SSDR;
@@ -1424,8 +1474,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        }
 
        /* Setup DMA if requested */
-       drv_data->tx_channel = -1;
-       drv_data->rx_channel = -1;
        if (platform_info->enable_dma) {
                status = pxa2xx_spi_dma_setup(drv_data);
                if (status) {
index 9f01e9c9aa753c913d791f9930c4d2649ed7ccdc..0a9b6390a817f60467b03f9e3fa589cc5bddf79f 100644 (file)
@@ -36,11 +36,6 @@ struct driver_data {
        /* PXA hookup */
        struct pxa2xx_spi_master *master_info;
 
-       /* PXA private DMA setup stuff */
-       int rx_channel;
-       int tx_channel;
-       u32 *null_dma_buf;
-
        /* SSP register addresses */
        void __iomem *ioaddr;
        u32 ssdr_physical;
index f9189a0c8cec81f243c7e2ad4587356d13cf27a6..818843336932c9af8ea4a7bfe223888a179d31c6 100644 (file)
@@ -383,7 +383,8 @@ static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg)
        rspi_write8(rspi, data, reg);
 }
 
-static int qspi_set_send_trigger(struct rspi_data *rspi, unsigned int len)
+static unsigned int qspi_set_send_trigger(struct rspi_data *rspi,
+                                         unsigned int len)
 {
        unsigned int n;
 
@@ -724,25 +725,25 @@ static int rspi_rz_transfer_one(struct spi_master *master,
 static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx,
                                        u8 *rx, unsigned int len)
 {
-       int i, n, ret;
-       int error;
+       unsigned int i, n;
+       int ret;
 
        while (len > 0) {
                n = qspi_set_send_trigger(rspi, len);
                qspi_set_receive_trigger(rspi, len);
                if (n == QSPI_BUFFER_SIZE) {
-                       error = rspi_wait_for_tx_empty(rspi);
-                       if (error < 0) {
+                       ret = rspi_wait_for_tx_empty(rspi);
+                       if (ret < 0) {
                                dev_err(&rspi->master->dev, "transmit timeout\n");
-                               return error;
+                               return ret;
                        }
                        for (i = 0; i < n; i++)
                                rspi_write_data(rspi, *tx++);
 
-                       error = rspi_wait_for_rx_full(rspi);
-                       if (error < 0) {
+                       ret = rspi_wait_for_rx_full(rspi);
+                       if (ret < 0) {
                                dev_err(&rspi->master->dev, "receive timeout\n");
-                               return error;
+                               return ret;
                        }
                        for (i = 0; i < n; i++)
                                *rx++ = rspi_read_data(rspi);
index f747ca26998624752cf1fbb6f9c051c477c49198..f36bc320a80799067e6402feeb2ebb64c4f58169 100644 (file)
@@ -501,7 +501,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
        }
 
        hw = spi_master_get_devdata(master);
-       memset(hw, 0, sizeof(struct s3c24xx_spi));
 
        hw->master = master;
        hw->pdata = pdata = dev_get_platdata(&pdev->dev);
index 133f53a9c1d4eb9b5235b88de03dac9c5d2ea27e..a339c1e9997a93a431cf5ce9be5947b6333ac3e9 100644 (file)
@@ -249,19 +249,23 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
        xspi->tx_ptr = t->tx_buf;
        xspi->rx_ptr = t->rx_buf;
        remaining_words = t->len / xspi->bytes_per_word;
-       reinit_completion(&xspi->done);
 
        if (xspi->irq >= 0 &&  remaining_words > xspi->buffer_size) {
+               u32 isr;
                use_irq = true;
-               xspi->write_fn(XSPI_INTR_TX_EMPTY,
-                               xspi->regs + XIPIF_V123B_IISR_OFFSET);
-               /* Enable the global IPIF interrupt */
-               xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
-                               xspi->regs + XIPIF_V123B_DGIER_OFFSET);
                /* Inhibit irq to avoid spurious irqs on tx_empty*/
                cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
                xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
                               xspi->regs + XSPI_CR_OFFSET);
+               /* ACK old irqs (if any) */
+               isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+               if (isr)
+                       xspi->write_fn(isr,
+                                      xspi->regs + XIPIF_V123B_IISR_OFFSET);
+               /* Enable the global IPIF interrupt */
+               xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+                               xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+               reinit_completion(&xspi->done);
        }
 
        while (remaining_words) {
@@ -302,8 +306,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
                remaining_words -= n_words;
        }
 
-       if (use_irq)
+       if (use_irq) {
                xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+               xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+       }
 
        return t->len;
 }
index 87b20a511a6ba66cc4ba084df028a3c073691aa2..f23f36ebaf3dc700447da2e4da6e9b1b28e8ed82 100644 (file)
@@ -214,6 +214,7 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
        case GQSPI_SELECT_FLASH_CS_BOTH:
                instanceptr->genfifocs = GQSPI_GENFIFO_CS_LOWER |
                        GQSPI_GENFIFO_CS_UPPER;
+               break;
        case GQSPI_SELECT_FLASH_CS_UPPER:
                instanceptr->genfifocs = GQSPI_GENFIFO_CS_UPPER;
                break;
index cf8b91b23a763d60f8253e3ef1e8ccd420e52a0c..24678ea45c570d8c758171074f5150d7269b838e 100644 (file)
@@ -539,8 +539,15 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg)
        if (!master->can_dma)
                return 0;
 
-       tx_dev = master->dma_tx->device->dev;
-       rx_dev = master->dma_rx->device->dev;
+       if (master->dma_tx)
+               tx_dev = master->dma_tx->device->dev;
+       else
+               tx_dev = &master->dev;
+
+       if (master->dma_rx)
+               rx_dev = master->dma_rx->device->dev;
+       else
+               rx_dev = &master->dev;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                if (!master->can_dma(master, msg->spi, xfer))
@@ -579,8 +586,15 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
        if (!master->cur_msg_mapped || !master->can_dma)
                return 0;
 
-       tx_dev = master->dma_tx->device->dev;
-       rx_dev = master->dma_rx->device->dev;
+       if (master->dma_tx)
+               tx_dev = master->dma_tx->device->dev;
+       else
+               tx_dev = &master->dev;
+
+       if (master->dma_rx)
+               rx_dev = master->dma_rx->device->dev;
+       else
+               rx_dev = &master->dev;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                if (!master->can_dma(master, msg->spi, xfer))
@@ -1740,6 +1754,20 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
  * other core methods are currently defined as inline functions.
  */
 
+static int __spi_validate_bits_per_word(struct spi_master *master, u8 bits_per_word)
+{
+       if (master->bits_per_word_mask) {
+               /* Only 32 bits fit in the mask */
+               if (bits_per_word > 32)
+                       return -EINVAL;
+               if (!(master->bits_per_word_mask &
+                               SPI_BPW_MASK(bits_per_word)))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * spi_setup - setup SPI mode and clock rate
  * @spi: the device whose settings are being modified
@@ -1798,6 +1826,9 @@ int spi_setup(struct spi_device *spi)
        if (!spi->bits_per_word)
                spi->bits_per_word = 8;
 
+       if (__spi_validate_bits_per_word(spi->master, spi->bits_per_word))
+               return -EINVAL;
+
        if (!spi->max_speed_hz)
                spi->max_speed_hz = spi->master->max_speed_hz;
 
@@ -1860,19 +1891,15 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 
                if (!xfer->speed_hz)
                        xfer->speed_hz = spi->max_speed_hz;
+               if (!xfer->speed_hz)
+                       xfer->speed_hz = master->max_speed_hz;
 
                if (master->max_speed_hz &&
                    xfer->speed_hz > master->max_speed_hz)
                        xfer->speed_hz = master->max_speed_hz;
 
-               if (master->bits_per_word_mask) {
-                       /* Only 32 bits fit in the mask */
-                       if (xfer->bits_per_word > 32)
-                               return -EINVAL;
-                       if (!(master->bits_per_word_mask &
-                                       BIT(xfer->bits_per_word - 1)))
-                               return -EINVAL;
-               }
+               if (__spi_validate_bits_per_word(master, xfer->bits_per_word))
+                       return -EINVAL;
 
                /*
                 * SPI transfer length should be multiple of SPI word size
index dd616ff0ffc52542c3c8f8aaaf7c7d30bb9fd219..c7de64171c452325ab43884b501977a33f724b93 100644 (file)
@@ -693,6 +693,7 @@ static struct class *spidev_class;
 #ifdef CONFIG_OF
 static const struct of_device_id spidev_dt_ids[] = {
        { .compatible = "rohm,dh2228fv" },
+       { .compatible = "lineartechnology,ltc2488" },
        {},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);
index b8ee81840666ad35b33d2cf2182b50db83415810..3f287c48e08204b353c27ea132f0e121956eb19c 100644 (file)
@@ -1,6 +1,6 @@
 config STAGING_BOARD
        bool "Staging Board Support"
-       depends on OF_ADDRESS
+       depends on OF_ADDRESS && OF_IRQ && CLKDEV_LOOKUP
        help
          Select to enable per-board staging support code.
 
index bfa42620a3f607857978895a49451b9177964374..940781183fac4e450503c7b3cd5df6c30bde6d0c 100644 (file)
@@ -1266,6 +1266,7 @@ static const struct das1800_board *das1800_probe(struct comedi_device *dev)
                if (index == das1801hc || index == das1802hc)
                        return board;
                index = das1801hc;
+               break;
        default:
                dev_err(dev->class_dev,
                        "Board model: probe returned 0x%x (unknown, please report)\n",
index 7125eb955ae50556f6fbd6c011aa1b8671d5f659..8a9d4a0de1298777d522a368a1ca6177cfdee06b 100644 (file)
@@ -31,7 +31,6 @@
 #define DEBUG_PORTAL_ALLOC
 #define DEBUG_SUBSYSTEM S_LND
 
-#include <asm/irq.h>
 #include <linux/crc32.h>
 #include <linux/errno.h>
 #include <linux/if.h>
index 9c934e6d2ea1114094921bd890eb0186a50f0e06..c61add46b4268b722eeaad74a0540a4a2c48f1e8 100644 (file)
@@ -40,7 +40,7 @@
 
 #define DEBUG_SUBSYSTEM D_OTHER
 
-#include <linux/unaligned/access_ok.h>
+#include <asm/unaligned.h>
 
 #include "../include/obd_support.h"
 #include "../include/lustre_debug.h"
index ed040fbb7df8d319ba39b61acf2009a163bf3745..69bdc8f29b59f4c1e1cbacabf7563a7ca1d66817 100644 (file)
@@ -1418,7 +1418,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
 
        priv->current_aid = conf->aid;
 
-       if (changed & BSS_CHANGED_BSSID) {
+       if (changed & BSS_CHANGED_BSSID && conf->bssid) {
                unsigned long flags;
 
                spin_lock_irqsave(&priv->lock, flags);
@@ -1483,8 +1483,9 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
-       if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) {
-               if (conf->assoc) {
+       if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) &&
+           priv->op_mode != NL80211_IFTYPE_AP) {
+               if (conf->assoc && conf->beacon_rate) {
                        CARDbUpdateTSF(priv, conf->beacon_rate->hw_value,
                                       conf->sync_tsf);
 
index f97323f19acfd8c988a2fbefb8b7f260ef7ece34..af572d71813531fa89453f5692ef834cb0bd856b 100644 (file)
@@ -701,7 +701,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
 
        priv->current_aid = conf->aid;
 
-       if (changed & BSS_CHANGED_BSSID)
+       if (changed & BSS_CHANGED_BSSID && conf->bssid)
                vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid);
 
 
index 4e68b62193ed7781d3c32f4160878809acfc546d..fd092909a4577a7c4a708516bf3344fee331ad84 100644 (file)
@@ -968,9 +968,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA;
 
        conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
-       if (hdr->flags & ISCSI_FLAG_CMD_READ) {
+       if (hdr->flags & ISCSI_FLAG_CMD_READ)
                cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
-       } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
+       else
                cmd->targ_xfer_tag = 0xFFFFFFFF;
        cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
        cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
@@ -3998,7 +3998,13 @@ get_immediate:
        }
 
 transport_err:
-       iscsit_take_action_for_connection_exit(conn);
+       /*
+        * Avoid the normal connection failure code-path if this connection
+        * is still within LOGIN mode, and iscsi_np process context is
+        * responsible for cleaning up the early connection failure.
+        */
+       if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN)
+               iscsit_take_action_for_connection_exit(conn);
 out:
        return 0;
 }
@@ -4082,7 +4088,7 @@ reject:
 
 int iscsi_target_rx_thread(void *arg)
 {
-       int ret;
+       int ret, rc;
        u8 buffer[ISCSI_HDR_LEN], opcode;
        u32 checksum = 0, digest = 0;
        struct iscsi_conn *conn = arg;
@@ -4092,10 +4098,16 @@ int iscsi_target_rx_thread(void *arg)
         * connection recovery / failure event can be triggered externally.
         */
        allow_signal(SIGINT);
+       /*
+        * Wait for iscsi_post_login_handler() to complete before allowing
+        * incoming iscsi/tcp socket I/O, and/or failing the connection.
+        */
+       rc = wait_for_completion_interruptible(&conn->rx_login_comp);
+       if (rc < 0)
+               return 0;
 
        if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
                struct completion comp;
-               int rc;
 
                init_completion(&comp);
                rc = wait_for_completion_interruptible(&comp);
@@ -4532,7 +4544,18 @@ static void iscsit_logout_post_handler_closesession(
        struct iscsi_conn *conn)
 {
        struct iscsi_session *sess = conn->sess;
-       int sleep = cmpxchg(&conn->tx_thread_active, true, false);
+       int sleep = 1;
+       /*
+        * Traditional iscsi/tcp will invoke this logic from TX thread
+        * context during session logout, so clear tx_thread_active and
+        * sleep if iscsit_close_connection() has not already occured.
+        *
+        * Since iser-target invokes this logic from it's own workqueue,
+        * always sleep waiting for RX/TX thread shutdown to complete
+        * within iscsit_close_connection().
+        */
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               sleep = cmpxchg(&conn->tx_thread_active, true, false);
 
        atomic_set(&conn->conn_logout_remove, 0);
        complete(&conn->conn_logout_comp);
@@ -4546,7 +4569,10 @@ static void iscsit_logout_post_handler_closesession(
 static void iscsit_logout_post_handler_samecid(
        struct iscsi_conn *conn)
 {
-       int sleep = cmpxchg(&conn->tx_thread_active, true, false);
+       int sleep = 1;
+
+       if (conn->conn_transport->transport_type == ISCSI_TCP)
+               sleep = cmpxchg(&conn->tx_thread_active, true, false);
 
        atomic_set(&conn->conn_logout_remove, 0);
        complete(&conn->conn_logout_comp);
@@ -4765,6 +4791,7 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
        struct iscsi_session *sess;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
        struct se_session *se_sess, *se_sess_tmp;
+       LIST_HEAD(free_list);
        int session_count = 0;
 
        spin_lock_bh(&se_tpg->session_lock);
@@ -4786,14 +4813,17 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
                }
                atomic_set(&sess->session_reinstatement, 1);
                spin_unlock(&sess->conn_lock);
-               spin_unlock_bh(&se_tpg->session_lock);
 
-               iscsit_free_session(sess);
-               spin_lock_bh(&se_tpg->session_lock);
+               list_move_tail(&se_sess->sess_list, &free_list);
+       }
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
 
+               iscsit_free_session(sess);
                session_count++;
        }
-       spin_unlock_bh(&se_tpg->session_lock);
 
        pr_debug("Released %d iSCSI Session(s) from Target Portal"
                        " Group: %hu\n", session_count, tpg->tpgt);
index 3d0fe4ff55904d00a702958a82413a33873de888..7e8f65e5448fdbda5645e3d5a836ad9f81408efa 100644 (file)
@@ -82,6 +82,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
        init_completion(&conn->conn_logout_comp);
        init_completion(&conn->rx_half_close_comp);
        init_completion(&conn->tx_half_close_comp);
+       init_completion(&conn->rx_login_comp);
        spin_lock_init(&conn->cmd_lock);
        spin_lock_init(&conn->conn_usage_lock);
        spin_lock_init(&conn->immed_queue_lock);
@@ -644,7 +645,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
                iscsit_start_nopin_timer(conn);
 }
 
-static int iscsit_start_kthreads(struct iscsi_conn *conn)
+int iscsit_start_kthreads(struct iscsi_conn *conn)
 {
        int ret = 0;
 
@@ -679,6 +680,7 @@ static int iscsit_start_kthreads(struct iscsi_conn *conn)
 
        return 0;
 out_tx:
+       send_sig(SIGINT, conn->tx_thread, 1);
        kthread_stop(conn->tx_thread);
        conn->tx_thread_active = false;
 out_bitmap:
@@ -689,7 +691,7 @@ out_bitmap:
        return ret;
 }
 
-int iscsi_post_login_handler(
+void iscsi_post_login_handler(
        struct iscsi_np *np,
        struct iscsi_conn *conn,
        u8 zero_tsih)
@@ -699,7 +701,6 @@ int iscsi_post_login_handler(
        struct se_session *se_sess = sess->se_sess;
        struct iscsi_portal_group *tpg = sess->tpg;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
-       int rc;
 
        iscsit_inc_conn_usage_count(conn);
 
@@ -739,10 +740,6 @@ int iscsi_post_login_handler(
                        sess->sess_ops->InitiatorName);
                spin_unlock_bh(&sess->conn_lock);
 
-               rc = iscsit_start_kthreads(conn);
-               if (rc)
-                       return rc;
-
                iscsi_post_login_start_timers(conn);
                /*
                 * Determine CPU mask to ensure connection's RX and TX kthreads
@@ -751,15 +748,20 @@ int iscsi_post_login_handler(
                iscsit_thread_get_cpumask(conn);
                conn->conn_rx_reset_cpumask = 1;
                conn->conn_tx_reset_cpumask = 1;
-
+               /*
+                * Wakeup the sleeping iscsi_target_rx_thread() now that
+                * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
+                */
+               complete(&conn->rx_login_comp);
                iscsit_dec_conn_usage_count(conn);
+
                if (stop_timer) {
                        spin_lock_bh(&se_tpg->session_lock);
                        iscsit_stop_time2retain_timer(sess);
                        spin_unlock_bh(&se_tpg->session_lock);
                }
                iscsit_dec_session_usage_count(sess);
-               return 0;
+               return;
        }
 
        iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1);
@@ -800,10 +802,6 @@ int iscsi_post_login_handler(
                " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
        spin_unlock_bh(&se_tpg->session_lock);
 
-       rc = iscsit_start_kthreads(conn);
-       if (rc)
-               return rc;
-
        iscsi_post_login_start_timers(conn);
        /*
         * Determine CPU mask to ensure connection's RX and TX kthreads
@@ -812,10 +810,12 @@ int iscsi_post_login_handler(
        iscsit_thread_get_cpumask(conn);
        conn->conn_rx_reset_cpumask = 1;
        conn->conn_tx_reset_cpumask = 1;
-
+       /*
+        * Wakeup the sleeping iscsi_target_rx_thread() now that
+        * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
+        */
+       complete(&conn->rx_login_comp);
        iscsit_dec_conn_usage_count(conn);
-
-       return 0;
 }
 
 static void iscsi_handle_login_thread_timeout(unsigned long data)
@@ -1380,23 +1380,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        if (ret < 0)
                goto new_sess_out;
 
-       if (!conn->sess) {
-               pr_err("struct iscsi_conn session pointer is NULL!\n");
-               goto new_sess_out;
-       }
-
        iscsi_stop_login_thread_timer(np);
 
-       if (signal_pending(current))
-               goto new_sess_out;
-
        if (ret == 1) {
                tpg_np = conn->tpg_np;
 
-               ret = iscsi_post_login_handler(np, conn, zero_tsih);
-               if (ret < 0)
-                       goto new_sess_out;
-
+               iscsi_post_login_handler(np, conn, zero_tsih);
                iscsit_deaccess_np(np, tpg, tpg_np);
        }
 
index 1c7358081533ad1e3fb0533f424fa7749feda7d5..57aa0d0fd820f330c271836ecdc02c5a067179b2 100644 (file)
@@ -12,7 +12,8 @@ extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
 extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
 extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
 extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
-extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
+extern int iscsit_start_kthreads(struct iscsi_conn *);
+extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
 extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
                                bool, bool);
 extern int iscsi_target_login_thread(void *);
index 8c02fa34716fae5a40dbf8cb09357bba5df2e7bd..f9cde91418367071d08c3a3ebe08dc44a1a1abe3 100644 (file)
@@ -17,6 +17,7 @@
  ******************************************************************************/
 
 #include <linux/ctype.h>
+#include <linux/kthread.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
@@ -361,10 +362,24 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
                ntohl(login_rsp->statsn), login->rsp_length);
 
        padding = ((-login->rsp_length) & 3);
+       /*
+        * Before sending the last login response containing the transition
+        * bit for full-feature-phase, go ahead and start up TX/RX threads
+        * now to avoid potential resource allocation failures after the
+        * final login response has been sent.
+        */
+       if (login->login_complete) {
+               int rc = iscsit_start_kthreads(conn);
+               if (rc) {
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                           ISCSI_LOGIN_STATUS_NO_RESOURCES);
+                       return -1;
+               }
+       }
 
        if (conn->conn_transport->iscsit_put_login_tx(conn, login,
                                        login->rsp_length + padding) < 0)
-               return -1;
+               goto err;
 
        login->rsp_length               = 0;
        mutex_lock(&sess->cmdsn_mutex);
@@ -373,6 +388,23 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
        mutex_unlock(&sess->cmdsn_mutex);
 
        return 0;
+
+err:
+       if (login->login_complete) {
+               if (conn->rx_thread && conn->rx_thread_active) {
+                       send_sig(SIGINT, conn->rx_thread, 1);
+                       kthread_stop(conn->rx_thread);
+               }
+               if (conn->tx_thread && conn->tx_thread_active) {
+                       send_sig(SIGINT, conn->tx_thread, 1);
+                       kthread_stop(conn->tx_thread);
+               }
+               spin_lock(&iscsit_global->ts_bitmap_lock);
+               bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
+                                     get_order(1));
+               spin_unlock(&iscsit_global->ts_bitmap_lock);
+       }
+       return -1;
 }
 
 static void iscsi_target_sk_data_ready(struct sock *sk)
index 0b0de36474784987c781906243eabbed27ecab00..860e840461778271191ba4ee8f1a4011dba5e78c 100644 (file)
@@ -457,8 +457,15 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
                if (!strcmp(t->tf_ops->name, fo->name)) {
                        BUG_ON(atomic_read(&t->tf_access_cnt));
                        list_del(&t->tf_list);
+                       mutex_unlock(&g_tf_lock);
+                       /*
+                        * Wait for any outstanding fabric se_deve_entry->rcu_head
+                        * callbacks to complete post kfree_rcu(), before allowing
+                        * fabric driver unload of TFO->module to proceed.
+                        */
+                       rcu_barrier();
                        kfree(t);
-                       break;
+                       return;
                }
        }
        mutex_unlock(&g_tf_lock);
@@ -747,7 +754,7 @@ static ssize_t store_pi_prot_type(struct se_dev_attrib *da,
        if (!dev->transport->init_prot || !dev->transport->free_prot) {
                /* 0 is only allowed value for non-supporting backends */
                if (flag == 0)
-                       return 0;
+                       return count;
 
                pr_err("DIF protection not supported by backend: %s\n",
                       dev->transport->name);
@@ -1590,9 +1597,9 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
        u8 type = 0;
 
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
-               return 0;
+               return count;
        if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
-               return 0;
+               return count;
 
        if (dev->export_count) {
                pr_debug("Unable to process APTPL metadata while"
@@ -1658,22 +1665,32 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                 * PR APTPL Metadata for Reservation
                 */
                case Opt_res_holder:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        res_holder = arg;
                        break;
                case Opt_res_type:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        type = (u8)arg;
                        break;
                case Opt_res_scope:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        break;
                case Opt_res_all_tg_pt:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        all_tg_pt = (int)arg;
                        break;
                case Opt_mapped_lun:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        mapped_lun = (u64)arg;
                        break;
                /*
@@ -1701,14 +1718,20 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                        }
                        break;
                case Opt_tpgt:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        tpgt = (u16)arg;
                        break;
                case Opt_port_rtpi:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        break;
                case Opt_target_lun:
-                       match_int(args, &arg);
+                       ret = match_int(args, &arg);
+                       if (ret)
+                               goto out;
                        target_lun = (u64)arg;
                        break;
                default:
@@ -1985,7 +2008,7 @@ static ssize_t target_core_store_alua_lu_gp(
 
        lu_gp_mem = dev->dev_alua_lu_gp_mem;
        if (!lu_gp_mem)
-               return 0;
+               return count;
 
        if (count > LU_GROUP_NAME_BUF) {
                pr_err("ALUA LU Group Alias too large!\n");
index 62ea4e8e70a8935398f2a0e86fc44627dfa3368e..be9cefc07407e80ef5dd7dfcbd8a0d025faf97f6 100644 (file)
@@ -84,8 +84,16 @@ void target_backend_unregister(const struct target_backend_ops *ops)
        list_for_each_entry(tb, &backend_list, list) {
                if (tb->ops == ops) {
                        list_del(&tb->list);
+                       mutex_unlock(&backend_mutex);
+                       /*
+                        * Wait for any outstanding backend driver ->rcu_head
+                        * callbacks to complete post TBO->free_device() ->
+                        * call_rcu(), before allowing backend driver module
+                        * unload of target_backend_ops->owner to proceed.
+                        */
+                       rcu_barrier();
                        kfree(tb);
-                       break;
+                       return;
                }
        }
        mutex_unlock(&backend_mutex);
index 0fdbe43b7dad99479f7288584a0d95815c4dab72..5ab7100de17eb5694b162403ef43585c4bbceaf1 100644 (file)
@@ -1474,7 +1474,7 @@ core_scsi3_decode_spec_i_port(
        LIST_HEAD(tid_dest_list);
        struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
        unsigned char *buf, *ptr, proto_ident;
-       const unsigned char *i_str;
+       const unsigned char *i_str = NULL;
        char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN];
        sense_reason_t ret;
        u32 tpdl, tid_len = 0;
index 4703f403f31c0dd6cc9b4d31422bbc16387b20e7..384cf88944113892135b3ff253ed97bdc6b9c8b4 100644 (file)
@@ -333,6 +333,7 @@ static int rd_configure_device(struct se_device *dev)
        dev->dev_attrib.hw_block_size = RD_BLOCKSIZE;
        dev->dev_attrib.hw_max_sectors = UINT_MAX;
        dev->dev_attrib.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH;
+       dev->dev_attrib.is_nonrot = 1;
 
        rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++;
 
index b0744433315a80496a84d8d6f49e01300471f463..f87d4cef6d398c072e953e7eaa6b5d9d5b469d70 100644 (file)
@@ -454,10 +454,17 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
                    cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT)
                        buf[4] = 0x5;
                else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT ||
-                       cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
+                        cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
                        buf[4] = 0x4;
        }
 
+       /* logical unit supports type 1 and type 3 protection */
+       if ((dev->transport->get_device_type(dev) == TYPE_DISK) &&
+           (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) &&
+           (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)) {
+               buf[4] |= (0x3 << 3);
+       }
+
        /* Set HEADSUP, ORDSUP, SIMPSUP */
        buf[5] = 0x07;
 
@@ -1196,17 +1203,13 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
        struct se_dev_entry *deve;
        struct se_session *sess = cmd->se_sess;
        struct se_node_acl *nacl;
+       struct scsi_lun slun;
        unsigned char *buf;
        u32 lun_count = 0, offset = 8;
-
-       if (cmd->data_length < 16) {
-               pr_warn("REPORT LUNS allocation length %u too small\n",
-                       cmd->data_length);
-               return TCM_INVALID_CDB_FIELD;
-       }
+       __be32 len;
 
        buf = transport_kmap_data_sg(cmd);
-       if (!buf)
+       if (cmd->data_length && !buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
        /*
@@ -1214,11 +1217,9 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
         * coming via a target_core_mod PASSTHROUGH op, and not through
         * a $FABRIC_MOD.  In that case, report LUN=0 only.
         */
-       if (!sess) {
-               int_to_scsilun(0, (struct scsi_lun *)&buf[offset]);
-               lun_count = 1;
+       if (!sess)
                goto done;
-       }
+
        nacl = sess->se_node_acl;
 
        rcu_read_lock();
@@ -1229,10 +1230,12 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
                 * See SPC2-R20 7.19.
                 */
                lun_count++;
-               if ((offset + 8) > cmd->data_length)
+               if (offset >= cmd->data_length)
                        continue;
 
-               int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
+               int_to_scsilun(deve->mapped_lun, &slun);
+               memcpy(buf + offset, &slun,
+                      min(8u, cmd->data_length - offset));
                offset += 8;
        }
        rcu_read_unlock();
@@ -1241,12 +1244,22 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
         * See SPC3 r07, page 159.
         */
 done:
-       lun_count *= 8;
-       buf[0] = ((lun_count >> 24) & 0xff);
-       buf[1] = ((lun_count >> 16) & 0xff);
-       buf[2] = ((lun_count >> 8) & 0xff);
-       buf[3] = (lun_count & 0xff);
-       transport_kunmap_data_sg(cmd);
+       /*
+        * If no LUNs are accessible, report virtual LUN 0.
+        */
+       if (lun_count == 0) {
+               int_to_scsilun(0, &slun);
+               if (cmd->data_length > 8)
+                       memcpy(buf + offset, &slun,
+                              min(8u, cmd->data_length - offset));
+               lun_count = 1;
+       }
+
+       if (buf) {
+               len = cpu_to_be32(lun_count * 8);
+               memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
        return 0;
index 6509c61b96484993333a4198138945f43154fdfd..620dcd405ff6eec9ae65b0af8e93c25daae15d1f 100644 (file)
@@ -68,7 +68,7 @@ struct power_table {
  *     registered cooling device.
  * @cpufreq_state: integer value representing the current state of cpufreq
  *     cooling devices.
- * @cpufreq_val: integer value representing the absolute value of the clipped
+ * @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.
@@ -91,7 +91,7 @@ struct cpufreq_cooling_device {
        int id;
        struct thermal_cooling_device *cool_dev;
        unsigned int cpufreq_state;
-       unsigned int cpufreq_val;
+       unsigned int clipped_freq;
        unsigned int max_level;
        unsigned int *freq_table;       /* In descending order */
        struct cpumask allowed_cpus;
@@ -107,6 +107,9 @@ struct cpufreq_cooling_device {
 static DEFINE_IDR(cpufreq_idr);
 static DEFINE_MUTEX(cooling_cpufreq_lock);
 
+static unsigned int cpufreq_dev_count;
+
+static DEFINE_MUTEX(cooling_list_lock);
 static LIST_HEAD(cpufreq_dev_list);
 
 /**
@@ -185,14 +188,14 @@ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
 {
        struct cpufreq_cooling_device *cpufreq_dev;
 
-       mutex_lock(&cooling_cpufreq_lock);
+       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_cpufreq_lock);
+                       mutex_unlock(&cooling_list_lock);
                        return get_level(cpufreq_dev, freq);
                }
        }
-       mutex_unlock(&cooling_cpufreq_lock);
+       mutex_unlock(&cooling_list_lock);
 
        pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
        return THERMAL_CSTATE_INVALID;
@@ -215,29 +218,35 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
                                    unsigned long event, void *data)
 {
        struct cpufreq_policy *policy = data;
-       unsigned long max_freq = 0;
+       unsigned long clipped_freq;
        struct cpufreq_cooling_device *cpufreq_dev;
 
-       switch (event) {
+       if (event != CPUFREQ_ADJUST)
+               return NOTIFY_DONE;
 
-       case CPUFREQ_ADJUST:
-               mutex_lock(&cooling_cpufreq_lock);
-               list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
-                       if (!cpumask_test_cpu(policy->cpu,
-                                             &cpufreq_dev->allowed_cpus))
-                               continue;
+       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))
+                       continue;
 
-                       max_freq = cpufreq_dev->cpufreq_val;
+               /*
+                * policy->max is the maximum allowed frequency defined by user
+                * and clipped_freq is the maximum that thermal constraints
+                * allow.
+                *
+                * If clipped_freq is lower than policy->max, then we need to
+                * readjust policy->max.
+                *
+                * But, if clipped_freq is greater than policy->max, we don't
+                * need to do anything.
+                */
+               clipped_freq = cpufreq_dev->clipped_freq;
 
-                       if (policy->max != max_freq)
-                               cpufreq_verify_within_limits(policy, 0,
-                                                            max_freq);
-               }
-               mutex_unlock(&cooling_cpufreq_lock);
+               if (policy->max > clipped_freq)
+                       cpufreq_verify_within_limits(policy, 0, clipped_freq);
                break;
-       default:
-               return NOTIFY_DONE;
        }
+       mutex_unlock(&cooling_list_lock);
 
        return NOTIFY_OK;
 }
@@ -519,7 +528,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
 
        clip_freq = cpufreq_device->freq_table[state];
        cpufreq_device->cpufreq_state = state;
-       cpufreq_device->cpufreq_val = clip_freq;
+       cpufreq_device->clipped_freq = clip_freq;
 
        cpufreq_update_policy(cpu);
 
@@ -861,17 +870,19 @@ __cpufreq_cooling_register(struct device_node *np,
                        pr_debug("%s: freq:%u KHz\n", __func__, freq);
        }
 
-       cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0];
+       cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
        cpufreq_dev->cool_dev = cool_dev;
 
        mutex_lock(&cooling_cpufreq_lock);
 
+       mutex_lock(&cooling_list_lock);
+       list_add(&cpufreq_dev->node, &cpufreq_dev_list);
+       mutex_unlock(&cooling_list_lock);
+
        /* Register the notifier for first cpufreq cooling device */
-       if (list_empty(&cpufreq_dev_list))
+       if (!cpufreq_dev_count++)
                cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
                                          CPUFREQ_POLICY_NOTIFIER);
-       list_add(&cpufreq_dev->node, &cpufreq_dev_list);
-
        mutex_unlock(&cooling_cpufreq_lock);
 
        return cool_dev;
@@ -1013,13 +1024,17 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
                return;
 
        cpufreq_dev = cdev->devdata;
-       mutex_lock(&cooling_cpufreq_lock);
-       list_del(&cpufreq_dev->node);
 
        /* Unregister the notifier for the last cpufreq cooling device */
-       if (list_empty(&cpufreq_dev_list))
+       mutex_lock(&cooling_cpufreq_lock);
+       if (!--cpufreq_dev_count)
                cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
                                            CPUFREQ_POLICY_NOTIFIER);
+
+       mutex_lock(&cooling_list_lock);
+       list_del(&cpufreq_dev->node);
+       mutex_unlock(&cooling_list_lock);
+
        mutex_unlock(&cooling_cpufreq_lock);
 
        thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
index d5dd357ba57c4c6af785b4f915d9fccba6a4fa21..b49f97c734d00ddccb50379d3131c232651e96e5 100644 (file)
@@ -405,7 +405,6 @@ static SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
 static struct platform_driver hisi_thermal_driver = {
        .driver = {
                .name           = "hisi_thermal",
-               .owner          = THIS_MODULE,
                .pm             = &hisi_thermal_pm_ops,
                .of_match_table = of_hisi_thermal_match,
        },
index 4672250b329f4cec54ab243b55b41b127b1c48d0..7006860f2f3693b04ee44996c5085e2f94ceae44 100644 (file)
@@ -229,7 +229,8 @@ static int allocate_power(struct thermal_zone_device *tz,
        struct thermal_instance *instance;
        struct power_allocator_params *params = tz->governor_data;
        u32 *req_power, *max_power, *granted_power, *extra_actor_power;
-       u32 total_req_power, max_allocatable_power;
+       u32 *weighted_req_power;
+       u32 total_req_power, max_allocatable_power, total_weighted_req_power;
        u32 total_granted_power, power_range;
        int i, num_actors, total_weight, ret = 0;
        int trip_max_desired_temperature = params->trip_max_desired_temperature;
@@ -247,16 +248,17 @@ static int allocate_power(struct thermal_zone_device *tz,
        }
 
        /*
-        * We need to allocate three arrays of the same size:
-        * req_power, max_power and granted_power.  They are going to
-        * be needed until this function returns.  Allocate them all
-        * in one go to simplify the allocation and deallocation
-        * logic.
+        * We need to allocate five arrays of the same size:
+        * req_power, max_power, granted_power, extra_actor_power and
+        * weighted_req_power.  They are going to be needed until this
+        * function returns.  Allocate them all in one go to simplify
+        * the allocation and deallocation logic.
         */
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*max_power));
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*granted_power));
        BUILD_BUG_ON(sizeof(*req_power) != sizeof(*extra_actor_power));
-       req_power = devm_kcalloc(&tz->device, num_actors * 4,
+       BUILD_BUG_ON(sizeof(*req_power) != sizeof(*weighted_req_power));
+       req_power = devm_kcalloc(&tz->device, num_actors * 5,
                                 sizeof(*req_power), GFP_KERNEL);
        if (!req_power) {
                ret = -ENOMEM;
@@ -266,8 +268,10 @@ static int allocate_power(struct thermal_zone_device *tz,
        max_power = &req_power[num_actors];
        granted_power = &req_power[2 * num_actors];
        extra_actor_power = &req_power[3 * num_actors];
+       weighted_req_power = &req_power[4 * num_actors];
 
        i = 0;
+       total_weighted_req_power = 0;
        total_req_power = 0;
        max_allocatable_power = 0;
 
@@ -289,13 +293,14 @@ static int allocate_power(struct thermal_zone_device *tz,
                else
                        weight = instance->weight;
 
-               req_power[i] = frac_to_int(weight * req_power[i]);
+               weighted_req_power[i] = frac_to_int(weight * req_power[i]);
 
                if (power_actor_get_max_power(cdev, tz, &max_power[i]))
                        continue;
 
                total_req_power += req_power[i];
                max_allocatable_power += max_power[i];
+               total_weighted_req_power += weighted_req_power[i];
 
                i++;
        }
@@ -303,8 +308,9 @@ static int allocate_power(struct thermal_zone_device *tz,
        power_range = pid_controller(tz, current_temp, control_temp,
                                     max_allocatable_power);
 
-       divvy_up_power(req_power, max_power, num_actors, total_req_power,
-                      power_range, granted_power, extra_actor_power);
+       divvy_up_power(weighted_req_power, max_power, num_actors,
+                      total_weighted_req_power, power_range, granted_power,
+                      extra_actor_power);
 
        total_granted_power = 0;
        i = 0;
@@ -328,7 +334,7 @@ static int allocate_power(struct thermal_zone_device *tz,
                                      max_allocatable_power, current_temp,
                                      (s32)control_temp - (s32)current_temp);
 
-       devm_kfree(&tz->device, req_power);
+       kfree(req_power);
 unlock:
        mutex_unlock(&tz->lock);
 
@@ -420,7 +426,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
                return -EINVAL;
        }
 
-       params = devm_kzalloc(&tz->device, sizeof(*params), GFP_KERNEL);
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
        if (!params)
                return -ENOMEM;
 
@@ -462,14 +468,14 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
        return 0;
 
 free:
-       devm_kfree(&tz->device, params);
+       kfree(params);
        return ret;
 }
 
 static void power_allocator_unbind(struct thermal_zone_device *tz)
 {
        dev_dbg(&tz->device, "Unbinding from thermal zone %d\n", tz->id);
-       devm_kfree(&tz->device, tz->governor_data);
+       kfree(tz->governor_data);
        tz->governor_data = NULL;
 }
 
index c8e35c1a43dcfd19145a6d1e24b132b25b5c6169..e0da3865e0600f8f23b6368be63fd662d5dda6d1 100644 (file)
@@ -1,6 +1,6 @@
 config EXYNOS_THERMAL
        tristate "Exynos thermal management unit driver"
-       depends on OF
+       depends on THERMAL_OF
        help
          If you say yes here you get support for the TMU (Thermal Management
          Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
index 531f4b179871f63da7fea6f32af19b27af18e9a3..c96ff10b869efd941bfe8c32384d48b70b1c348d 100644 (file)
@@ -1296,7 +1296,6 @@ static struct thermal_zone_of_device_ops exynos_sensor_ops = {
 
 static int exynos_tmu_probe(struct platform_device *pdev)
 {
-       struct exynos_tmu_platform_data *pdata;
        struct exynos_tmu_data *data;
        int ret;
 
@@ -1318,8 +1317,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
        if (ret)
                goto err_sensor;
 
-       pdata = data->pdata;
-
        INIT_WORK(&data->irq_work, exynos_tmu_work);
 
        data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
@@ -1392,6 +1389,8 @@ err_clk_sec:
        if (!IS_ERR(data->clk_sec))
                clk_unprepare(data->clk_sec);
 err_sensor:
+       if (!IS_ERR_OR_NULL(data->regulator))
+               regulator_disable(data->regulator);
        thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
 
        return ret;
index 04659bfb888b73237257b75f944bf9130bc241b6..4ca211be4c0f197825be94f70be386af1c2cc33d 100644 (file)
@@ -1333,6 +1333,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
        return -ENODEV;
 
 unbind:
+       device_remove_file(&tz->device, &pos->weight_attr);
        device_remove_file(&tz->device, &pos->attr);
        sysfs_remove_link(&tz->device.kobj, pos->name);
        release_idr(&tz->idr, &tz->lock, pos->id);
index c9c27f69e101cfc9246a81ed1f187148b08193e6..ee8bfacf20716481a23a60325b5c99ba9da35508 100644 (file)
@@ -1108,19 +1108,29 @@ static void eraser(unsigned char c, struct tty_struct *tty)
  *     Locking: ctrl_lock
  */
 
-static void isig(int sig, struct tty_struct *tty)
+static void __isig(int sig, struct tty_struct *tty)
 {
-       struct n_tty_data *ldata = tty->disc_data;
        struct pid *tty_pgrp = tty_get_pgrp(tty);
        if (tty_pgrp) {
                kill_pgrp(tty_pgrp, sig, 1);
                put_pid(tty_pgrp);
        }
+}
 
-       if (!L_NOFLSH(tty)) {
+static void isig(int sig, struct tty_struct *tty)
+{
+       struct n_tty_data *ldata = tty->disc_data;
+
+       if (L_NOFLSH(tty)) {
+               /* signal only */
+               __isig(sig, tty);
+
+       } else { /* signal and flush */
                up_read(&tty->termios_rwsem);
                down_write(&tty->termios_rwsem);
 
+               __isig(sig, tty);
+
                /* clear echo buffer */
                mutex_lock(&ldata->output_lock);
                ldata->echo_head = ldata->echo_tail = 0;
index 76e65b714471d9eeb11ea12593adea987205daaa..15b4079a335e886ca62c422970c80ba8c93f9dfb 100644 (file)
@@ -1185,7 +1185,7 @@ config SERIAL_SC16IS7XX_CORE
 config SERIAL_SC16IS7XX
         tristate "SC16IS7xx serial support"
         select SERIAL_CORE
-        depends on I2C || SPI_MASTER
+        depends on (SPI_MASTER && !I2C) || I2C
         help
           This selects support for SC16IS7xx serial ports.
           Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
index 50cf5b10ceed98022cbc44609acd280ef2beba81..fd27e986b1dd3437dfd2560ec11efd8def7bf254 100644 (file)
@@ -2310,8 +2310,8 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
        void __iomem *base;
 
        base = devm_ioremap_resource(dev, mmiobase);
-       if (!base)
-               return -ENOMEM;
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        index = pl011_probe_dt_alias(index, dev);
 
index a57301a6fe427027788aa2153547928597c71ed1..679709f51fd4cfe4739fc2edb433cc4badaf0227 100644 (file)
@@ -950,7 +950,7 @@ static int etraxfs_uart_remove(struct platform_device *pdev)
 
        port = platform_get_drvdata(pdev);
        uart_remove_one_port(&etraxfs_uart_driver, port);
-       etraxfs_uart_ports[pdev->id] = NULL;
+       etraxfs_uart_ports[port->line] = NULL;
 
        return 0;
 }
index 2c90dc31bfaabc0242e168dd688faadadd9f164a..54fdc7866ea17423836827ee374c1ecfd0b5257d 100644 (file)
@@ -1121,11 +1121,6 @@ static int imx_startup(struct uart_port *port)
 
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
-       /* Can we enable the DMA support? */
-       if (is_imx6q_uart(sport) && !uart_console(port) &&
-           !sport->dma_is_inited)
-               imx_uart_dma_init(sport);
-
        spin_lock_irqsave(&sport->port.lock, flags);
        /* Reset fifo's and state machines */
        i = 100;
@@ -1143,9 +1138,6 @@ static int imx_startup(struct uart_port *port)
        writel(USR1_RTSD, sport->port.membase + USR1);
        writel(USR2_ORE, sport->port.membase + USR2);
 
-       if (sport->dma_is_inited && !sport->dma_is_enabled)
-               imx_enable_dma(sport);
-
        temp = readl(sport->port.membase + UCR1);
        temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
 
@@ -1316,6 +1308,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        } else {
                                ucr2 |= UCR2_CTSC;
                        }
+
+                       /* Can we enable the DMA support? */
+                       if (is_imx6q_uart(sport) && !uart_console(port)
+                               && !sport->dma_is_inited)
+                               imx_uart_dma_init(sport);
                } else {
                        termios->c_cflag &= ~CRTSCTS;
                }
@@ -1432,6 +1429,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
                imx_enable_ms(&sport->port);
 
+       if (sport->dma_is_inited && !sport->dma_is_enabled)
+               imx_enable_dma(sport);
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
index 9e6576004a427e51cac6f1b59237248a706332f8..5ccc698cbbfa1ad9bde91200ea5907753fbb4b78 100644 (file)
@@ -354,6 +354,26 @@ static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)
                     (reg << SC16IS7XX_REG_SHIFT) | port->line, val);
 }
 
+static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen)
+{
+       struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+       u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | port->line;
+
+       regcache_cache_bypass(s->regmap, true);
+       regmap_raw_read(s->regmap, addr, s->buf, rxlen);
+       regcache_cache_bypass(s->regmap, false);
+}
+
+static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
+{
+       struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+       u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | port->line;
+
+       regcache_cache_bypass(s->regmap, true);
+       regmap_raw_write(s->regmap, addr, s->buf, to_send);
+       regcache_cache_bypass(s->regmap, false);
+}
+
 static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
                                  u8 mask, u8 val)
 {
@@ -508,10 +528,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
                        s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
                        bytes_read = 1;
                } else {
-                       regcache_cache_bypass(s->regmap, true);
-                       regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG,
-                                       s->buf, rxlen);
-                       regcache_cache_bypass(s->regmap, false);
+                       sc16is7xx_fifo_read(port, rxlen);
                        bytes_read = rxlen;
                }
 
@@ -591,9 +608,8 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
                        s->buf[i] = xmit->buf[xmit->tail];
                        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                }
-               regcache_cache_bypass(s->regmap, true);
-               regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send);
-               regcache_cache_bypass(s->regmap, false);
+
+               sc16is7xx_fifo_write(port, to_send);
        }
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
index 7ae1592f7ec9731c4dab1d3a12b980420aade634..f36852067f20e61ebaf67269ec08c37ea342c06a 100644 (file)
@@ -1418,7 +1418,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        mutex_lock(&port->mutex);
        uart_shutdown(tty, state);
        tty_port_tty_set(port, NULL);
-       tty->closing = 0;
+
        spin_lock_irqsave(&port->lock, flags);
 
        if (port->blocked_open) {
@@ -1444,6 +1444,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        mutex_unlock(&port->mutex);
 
        tty_ldisc_flush(tty);
+       tty->closing = 0;
 }
 
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
index ea27804d87af9ec2485b1043f8ad97b30c05713f..381a2b13682c1a587a81e9bab781bcccdc669332 100644 (file)
@@ -356,6 +356,7 @@ int paste_selection(struct tty_struct *tty)
                        schedule();
                        continue;
                }
+               __set_current_state(TASK_RUNNING);
                count = sel_buffer_lth - pasted;
                count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
                                              count);
index 8fe52989b380155926c6865721e9ba16e2a60685..4462d167900c515abbf205b2b6134016c0933390 100644 (file)
@@ -742,6 +742,8 @@ static void visual_init(struct vc_data *vc, int num, int init)
        __module_get(vc->vc_sw->owner);
        vc->vc_num = num;
        vc->vc_display_fg = &master_display_fg;
+       if (vc->vc_uni_pagedir_loc)
+               con_free_unimap(vc);
        vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
        vc->vc_uni_pagedir = NULL;
        vc->vc_hi_font_mask = 0;
index 74fea4fa41b156248ce6d7116db02b54990066a9..3ad48e1c0c57e1722311c8393ad3bd21712fa1e7 100644 (file)
@@ -1024,7 +1024,18 @@ static struct platform_driver ci_hdrc_driver = {
        },
 };
 
-module_platform_driver(ci_hdrc_driver);
+static int __init ci_hdrc_platform_register(void)
+{
+       ci_hdrc_host_driver_init();
+       return platform_driver_register(&ci_hdrc_driver);
+}
+module_init(ci_hdrc_platform_register);
+
+static void __exit ci_hdrc_platform_unregister(void)
+{
+       platform_driver_unregister(&ci_hdrc_driver);
+}
+module_exit(ci_hdrc_platform_unregister);
 
 MODULE_ALIAS("platform:ci_hdrc");
 MODULE_LICENSE("GPL v2");
index 6cf87b8b13a8a606b5ccf680e4635fcbc44874a1..7161439def19aa265c9f36530d3d97d63ecc51a7 100644 (file)
@@ -249,9 +249,12 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
        rdrv->name      = "host";
        ci->roles[CI_ROLE_HOST] = rdrv;
 
+       return 0;
+}
+
+void ci_hdrc_host_driver_init(void)
+{
        ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
        orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
        ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
-
-       return 0;
 }
index 5707bf379bfb4b7ce98ff4a79d585619d1c64b48..0f12f131bdd3f22671eaf170476e2511950fa1be 100644 (file)
@@ -5,6 +5,7 @@
 
 int ci_hdrc_host_init(struct ci_hdrc *ci);
 void ci_hdrc_host_destroy(struct ci_hdrc *ci);
+void ci_hdrc_host_driver_init(void);
 
 #else
 
@@ -18,6 +19,11 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
 
 }
 
+static void ci_hdrc_host_driver_init(void)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
index 519a77ba214cce4c4580b54856c74ba9e3af5342..b30e7423549b04b0e7d442a128048b4221c68062 100644 (file)
@@ -1944,6 +1944,7 @@ static void __exit acm_exit(void)
        usb_deregister(&acm_driver);
        tty_unregister_driver(acm_tty_driver);
        put_tty_driver(acm_tty_driver);
+       idr_destroy(&acm_minors);
 }
 
 module_init(acm_init);
index 0e6f968e93fe8a9f31f7de7199fa778b60b2f900..01c0c0477a9e93d1c8e1150b80763f5ee6c90a02 100644 (file)
@@ -242,7 +242,7 @@ static int __init ulpi_init(void)
 {
        return bus_register(&ulpi_bus);
 }
-module_init(ulpi_init);
+subsys_initcall(ulpi_init);
 
 static void __exit ulpi_exit(void)
 {
index be5b2074f9066a8c9ca3e79289117f67d52b1063..cbcd0920fb5121ba44bd7c87de9a3b3fdd9f51d6 100644 (file)
@@ -1022,9 +1022,12 @@ static int register_root_hub(struct usb_hcd *hcd)
                                dev_name(&usb_dev->dev), retval);
                return (retval < 0) ? retval : -EMSGSIZE;
        }
-       if (usb_dev->speed == USB_SPEED_SUPER) {
+
+       if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
                retval = usb_get_bos_descriptor(usb_dev);
-               if (retval < 0) {
+               if (!retval) {
+                       usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
+               } else if (usb_dev->speed == USB_SPEED_SUPER) {
                        mutex_unlock(&usb_bus_list_lock);
                        dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
                                        dev_name(&usb_dev->dev), retval);
index 43cb2f2e3b4375aee6c362e8b08d5f2b71865d8f..73dfa194160b78fba6bec233b667b00bceac6cb1 100644 (file)
@@ -122,7 +122,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
        return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
 
-static int usb_device_supports_lpm(struct usb_device *udev)
+int usb_device_supports_lpm(struct usb_device *udev)
 {
        /* USB 2.1 (and greater) devices indicate LPM support through
         * their USB 2.0 Extended Capabilities BOS descriptor.
index 7eb1e26798e5f293a3f2bc508dd268bbecdb63f1..457255a3306a3c2837674d22aa9560bf30842220 100644 (file)
@@ -65,6 +65,7 @@ extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
 extern int usb_major_init(void);
 extern void usb_major_cleanup(void);
+extern int usb_device_supports_lpm(struct usb_device *udev);
 
 #ifdef CONFIG_PM
 
index e5b546f1152ef0f8c527fb19d776372cb0877f69..c3cc1a78d1e2b3470402f7cae45e4f11aa02dc0a 100644 (file)
@@ -72,17 +72,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "%s\n", __func__);
 
        /* Backup Host regs */
-       hr = hsotg->hr_backup;
-       if (!hr) {
-               hr = devm_kzalloc(hsotg->dev, sizeof(*hr), GFP_KERNEL);
-               if (!hr) {
-                       dev_err(hsotg->dev, "%s: can't allocate host regs\n",
-                                       __func__);
-                       return -ENOMEM;
-               }
-
-               hsotg->hr_backup = hr;
-       }
+       hr = &hsotg->hr_backup;
        hr->hcfg = readl(hsotg->regs + HCFG);
        hr->haintmsk = readl(hsotg->regs + HAINTMSK);
        for (i = 0; i < hsotg->core_params->host_channels; ++i)
@@ -90,6 +80,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
 
        hr->hprt0 = readl(hsotg->regs + HPRT0);
        hr->hfir = readl(hsotg->regs + HFIR);
+       hr->valid = true;
 
        return 0;
 }
@@ -109,12 +100,13 @@ static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "%s\n", __func__);
 
        /* Restore host regs */
-       hr = hsotg->hr_backup;
-       if (!hr) {
+       hr = &hsotg->hr_backup;
+       if (!hr->valid) {
                dev_err(hsotg->dev, "%s: no host registers to restore\n",
                                __func__);
                return -EINVAL;
        }
+       hr->valid = false;
 
        writel(hr->hcfg, hsotg->regs + HCFG);
        writel(hr->haintmsk, hsotg->regs + HAINTMSK);
@@ -152,17 +144,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "%s\n", __func__);
 
        /* Backup dev regs */
-       dr = hsotg->dr_backup;
-       if (!dr) {
-               dr = devm_kzalloc(hsotg->dev, sizeof(*dr), GFP_KERNEL);
-               if (!dr) {
-                       dev_err(hsotg->dev, "%s: can't allocate device regs\n",
-                                       __func__);
-                       return -ENOMEM;
-               }
-
-               hsotg->dr_backup = dr;
-       }
+       dr = &hsotg->dr_backup;
 
        dr->dcfg = readl(hsotg->regs + DCFG);
        dr->dctl = readl(hsotg->regs + DCTL);
@@ -195,7 +177,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
                dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i));
                dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i));
        }
-
+       dr->valid = true;
        return 0;
 }
 
@@ -215,12 +197,13 @@ static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "%s\n", __func__);
 
        /* Restore dev regs */
-       dr = hsotg->dr_backup;
-       if (!dr) {
+       dr = &hsotg->dr_backup;
+       if (!dr->valid) {
                dev_err(hsotg->dev, "%s: no device registers to restore\n",
                                __func__);
                return -EINVAL;
        }
+       dr->valid = false;
 
        writel(dr->dcfg, hsotg->regs + DCFG);
        writel(dr->dctl, hsotg->regs + DCTL);
@@ -268,17 +251,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
        int i;
 
        /* Backup global regs */
-       gr = hsotg->gr_backup;
-       if (!gr) {
-               gr = devm_kzalloc(hsotg->dev, sizeof(*gr), GFP_KERNEL);
-               if (!gr) {
-                       dev_err(hsotg->dev, "%s: can't allocate global regs\n",
-                                       __func__);
-                       return -ENOMEM;
-               }
-
-               hsotg->gr_backup = gr;
-       }
+       gr = &hsotg->gr_backup;
 
        gr->gotgctl = readl(hsotg->regs + GOTGCTL);
        gr->gintmsk = readl(hsotg->regs + GINTMSK);
@@ -291,6 +264,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
        for (i = 0; i < MAX_EPS_CHANNELS; i++)
                gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i));
 
+       gr->valid = true;
        return 0;
 }
 
@@ -309,12 +283,13 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "%s\n", __func__);
 
        /* Restore global regs */
-       gr = hsotg->gr_backup;
-       if (!gr) {
+       gr = &hsotg->gr_backup;
+       if (!gr->valid) {
                dev_err(hsotg->dev, "%s: no global registers to restore\n",
                                __func__);
                return -EINVAL;
        }
+       gr->valid = false;
 
        writel(0xffffffff, hsotg->regs + GINTSTS);
        writel(gr->gotgctl, hsotg->regs + GOTGCTL);
index 53b8de03f1028c9982e0a403fad2d487ca09bd45..0ed87620941b5606b83f7e628439266ca7831e18 100644 (file)
@@ -492,6 +492,7 @@ struct dwc2_gregs_backup {
        u32 gdfifocfg;
        u32 dtxfsiz[MAX_EPS_CHANNELS];
        u32 gpwrdn;
+       bool valid;
 };
 
 /**
@@ -521,6 +522,7 @@ struct dwc2_dregs_backup {
        u32 doepctl[MAX_EPS_CHANNELS];
        u32 doeptsiz[MAX_EPS_CHANNELS];
        u32 doepdma[MAX_EPS_CHANNELS];
+       bool valid;
 };
 
 /**
@@ -538,6 +540,7 @@ struct dwc2_hregs_backup {
        u32 hcintmsk[MAX_EPS_CHANNELS];
        u32 hprt0;
        u32 hfir;
+       bool valid;
 };
 
 /**
@@ -705,9 +708,9 @@ struct dwc2_hsotg {
        struct work_struct wf_otg;
        struct timer_list wkp_timer;
        enum dwc2_lx_state lx_state;
-       struct dwc2_gregs_backup *gr_backup;
-       struct dwc2_dregs_backup *dr_backup;
-       struct dwc2_hregs_backup *hr_backup;
+       struct dwc2_gregs_backup gr_backup;
+       struct dwc2_dregs_backup dr_backup;
+       struct dwc2_hregs_backup hr_backup;
 
        struct dentry *debug_root;
        struct debugfs_regset32 *regset;
index b10377c650646560996f14b7d51e5d0cb0b90dfc..f845c41fe9e5e8c788c35d0fd7711b54debbe97e 100644 (file)
@@ -359,10 +359,9 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
 
 /* Caller must hold driver lock */
 static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
-                               struct dwc2_hcd_urb *urb, void **ep_handle,
-                               gfp_t mem_flags)
+                               struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
+                               struct dwc2_qtd *qtd)
 {
-       struct dwc2_qtd *qtd;
        u32 intr_mask;
        int retval;
        int dev_speed;
@@ -386,18 +385,15 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                        return -ENODEV;
        }
 
-       qtd = kzalloc(sizeof(*qtd), mem_flags);
        if (!qtd)
-               return -ENOMEM;
+               return -EINVAL;
 
        dwc2_hcd_qtd_init(qtd, urb);
-       retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
-                                 mem_flags);
+       retval = dwc2_hcd_qtd_add(hsotg, qtd, qh);
        if (retval) {
                dev_err(hsotg->dev,
                        "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
                        retval);
-               kfree(qtd);
                return retval;
        }
 
@@ -2445,6 +2441,9 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        u32 tflags = 0;
        void *buf;
        unsigned long flags;
+       struct dwc2_qh *qh;
+       bool qh_allocated = false;
+       struct dwc2_qtd *qtd;
 
        if (dbg_urb(urb)) {
                dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
@@ -2523,15 +2522,32 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                                                 urb->iso_frame_desc[i].length);
 
        urb->hcpriv = dwc2_urb;
+       qh = (struct dwc2_qh *) ep->hcpriv;
+       /* Create QH for the endpoint if it doesn't exist */
+       if (!qh) {
+               qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags);
+               if (!qh) {
+                       retval = -ENOMEM;
+                       goto fail0;
+               }
+               ep->hcpriv = qh;
+               qh_allocated = true;
+       }
+
+       qtd = kzalloc(sizeof(*qtd), mem_flags);
+       if (!qtd) {
+               retval = -ENOMEM;
+               goto fail1;
+       }
 
        spin_lock_irqsave(&hsotg->lock, flags);
        retval = usb_hcd_link_urb_to_ep(hcd, urb);
        if (retval)
-               goto fail1;
+               goto fail2;
 
-       retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
+       retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd);
        if (retval)
-               goto fail2;
+               goto fail3;
 
        if (alloc_bandwidth) {
                dwc2_allocate_bus_bandwidth(hcd,
@@ -2543,12 +2559,25 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
        return 0;
 
-fail2:
+fail3:
        dwc2_urb->priv = NULL;
        usb_hcd_unlink_urb_from_ep(hcd, urb);
-fail1:
+fail2:
        spin_unlock_irqrestore(&hsotg->lock, flags);
        urb->hcpriv = NULL;
+       kfree(qtd);
+fail1:
+       if (qh_allocated) {
+               struct dwc2_qtd *qtd2, *qtd2_tmp;
+
+               ep->hcpriv = NULL;
+               dwc2_hcd_qh_unlink(hsotg, qh);
+               /* Free each QTD in the QH's QTD list */
+               list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list,
+                                                        qtd_list_entry)
+                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh);
+               dwc2_hcd_qh_free(hsotg, qh);
+       }
 fail0:
        kfree(dwc2_urb);
 
index 7b5841c4003301b349b499fdfb500e860ba86c74..fc1054965552aca51fa7f9bcdf87bae769077437 100644 (file)
@@ -463,6 +463,9 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
 /* Schedule Queue Functions */
 /* Implemented in hcd_queue.c */
 extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
+extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+                                         struct dwc2_hcd_urb *urb,
+                                         gfp_t mem_flags);
 extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
 extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
 extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
@@ -471,7 +474,7 @@ extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 
 extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
 extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                           struct dwc2_qh **qh, gfp_t mem_flags);
+                           struct dwc2_qh *qh);
 
 /* Unlinks and frees a QTD */
 static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
index 9b5c36256627b0b163fb25fc7549c46e1944ed35..3ad63d392e13f51c5e9aa8a31069de3795cdf86f 100644 (file)
@@ -191,7 +191,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
  *
  * Return: Pointer to the newly allocated QH, or NULL on error
  */
-static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
                                          struct dwc2_hcd_urb *urb,
                                          gfp_t mem_flags)
 {
@@ -767,57 +767,32 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
  *
  * @hsotg:        The DWC HCD structure
  * @qtd:          The QTD to add
- * @qh:           Out parameter to return queue head
- * @atomic_alloc: Flag to do atomic alloc if needed
+ * @qh:           Queue head to add qtd to
  *
  * Return: 0 if successful, negative error code otherwise
  *
- * Finds the correct QH to place the QTD into. If it does not find a QH, it
- * will create a new QH. If the QH to which the QTD is added is not currently
- * scheduled, it is placed into the proper schedule based on its EP type.
+ * If the QH to which the QTD is added is not currently scheduled, it is placed
+ * into the proper schedule based on its EP type.
  */
 int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
-                    struct dwc2_qh **qh, gfp_t mem_flags)
+                    struct dwc2_qh *qh)
 {
-       struct dwc2_hcd_urb *urb = qtd->urb;
-       int allocated = 0;
        int retval;
 
-       /*
-        * Get the QH which holds the QTD-list to insert to. Create QH if it
-        * doesn't exist.
-        */
-       if (*qh == NULL) {
-               *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
-               if (*qh == NULL)
-                       return -ENOMEM;
-               allocated = 1;
+       if (unlikely(!qh)) {
+               dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
+               retval = -EINVAL;
+               goto fail;
        }
 
-       retval = dwc2_hcd_qh_add(hsotg, *qh);
+       retval = dwc2_hcd_qh_add(hsotg, qh);
        if (retval)
                goto fail;
 
-       qtd->qh = *qh;
-       list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
+       qtd->qh = qh;
+       list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
 
        return 0;
-
 fail:
-       if (allocated) {
-               struct dwc2_qtd *qtd2, *qtd2_tmp;
-               struct dwc2_qh *qh_tmp = *qh;
-
-               *qh = NULL;
-               dwc2_hcd_qh_unlink(hsotg, qh_tmp);
-
-               /* Free each QTD in the QH's QTD list */
-               list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
-                                        qtd_list_entry)
-                       dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
-
-               dwc2_hcd_qh_free(hsotg, qh_tmp);
-       }
-
        return retval;
 }
index 5c110d8e293b534df24ff45f784f02a3d84d5644..ff5773c66b84f22b8ffabe986546d2810d0a9864 100644 (file)
@@ -446,10 +446,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        /* Select the HS PHY interface */
        switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
        case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
-               if (!strncmp(dwc->hsphy_interface, "utmi", 4)) {
+               if (dwc->hsphy_interface &&
+                               !strncmp(dwc->hsphy_interface, "utmi", 4)) {
                        reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
                        break;
-               } else if (!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
+               } else if (dwc->hsphy_interface &&
+                               !strncmp(dwc->hsphy_interface, "ulpi", 4)) {
                        reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
                        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
                } else {
index 2ef3c8d6a9dbd3b5b8270cb5af230d793e0d7230..69e769c35cf5dc798fb34a6924c19726690592a2 100644 (file)
@@ -727,6 +727,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
                ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
                break;
+       case USB_REQ_SET_INTERFACE:
+               dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
+               dwc->start_config_issued = false;
+               /* Fall through */
        default:
                dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
index 4e3447bbd0976e42eda4ec2a5d71f6cb4e9f75c9..58b4657fc721d3dabda76b2138ea6c30d539992c 100644 (file)
@@ -1758,10 +1758,13 @@ unknown:
                 * take such requests too, if that's ever needed:  to work
                 * in config 0, etc.
                 */
-               list_for_each_entry(f, &cdev->config->functions, list)
-                       if (f->req_match && f->req_match(f, ctrl))
-                               goto try_fun_setup;
-               f = NULL;
+               if (cdev->config) {
+                       list_for_each_entry(f, &cdev->config->functions, list)
+                               if (f->req_match && f->req_match(f, ctrl))
+                                       goto try_fun_setup;
+                       f = NULL;
+               }
+
                switch (ctrl->bRequestType & USB_RECIP_MASK) {
                case USB_RECIP_INTERFACE:
                        if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
index 0495c94a23d7e96a9c3554b99893b6b0f63e7302..289e20119fea25eb1d670c2abbef7ca3f671633e 100644 (file)
@@ -571,7 +571,7 @@ static struct config_group *function_make(
        if (IS_ERR(fi))
                return ERR_CAST(fi);
 
-       ret = config_item_set_name(&fi->group.cg_item, name);
+       ret = config_item_set_name(&fi->group.cg_item, "%s", name);
        if (ret) {
                usb_put_function_instance(fi);
                return ERR_PTR(ret);
index 45b8c8b338df7a877cebe8ef6743a675c31aa31e..6e7be91e6097cf0cfb4d6106decc141aeb8a5eb3 100644 (file)
@@ -924,7 +924,8 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 
        kiocb->private = p;
 
-       kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+       if (p->aio)
+               kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
        res = ffs_epfile_io(kiocb->ki_filp, p);
        if (res == -EIOCBQUEUED)
@@ -968,7 +969,8 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 
        kiocb->private = p;
 
-       kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+       if (p->aio)
+               kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
        res = ffs_epfile_io(kiocb->ki_filp, p);
        if (res == -EIOCBQUEUED)
index f7f35a36c09a06eab17ef2e5af013ee3de2b5b8e..6df9715a4bcd31179cb190100df45b2dd975a0d2 100644 (file)
@@ -699,6 +699,10 @@ static inline int hidg_get_minor(void)
        int ret;
 
        ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL);
+       if (ret >= HIDG_MINORS) {
+               ida_simple_remove(&hidg_ida, ret);
+               ret = -ENODEV;
+       }
 
        return ret;
 }
index d2259c6639960c55c76239401148bbcc2ec1f449..f936268d26c6aaa9a5601614adf2e90319e0d364 100644 (file)
@@ -2786,7 +2786,7 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns)
                return -EINVAL;
        }
 
-       curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
+       curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL);
        if (unlikely(!curlun))
                return -ENOMEM;
 
@@ -2796,8 +2796,6 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns)
        common->luns = curlun;
        common->nluns = nluns;
 
-       pr_info("Number of LUNs=%d\n", common->nluns);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(fsg_common_set_nluns);
@@ -3563,14 +3561,26 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
        struct fsg_opts *opts = fsg_opts_from_func_inst(fi);
        struct fsg_common *common = opts->common;
        struct fsg_dev *fsg;
+       unsigned nluns, i;
 
        fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
        if (unlikely(!fsg))
                return ERR_PTR(-ENOMEM);
 
        mutex_lock(&opts->lock);
+       if (!opts->refcnt) {
+               for (nluns = i = 0; i < FSG_MAX_LUNS; ++i)
+                       if (common->luns[i])
+                               nluns = i + 1;
+               if (!nluns)
+                       pr_warn("No LUNS defined, continuing anyway\n");
+               else
+                       common->nluns = nluns;
+               pr_info("Number of LUNs=%u\n", common->nluns);
+       }
        opts->refcnt++;
        mutex_unlock(&opts->lock);
+
        fsg->function.name      = FSG_DRIVER_DESC;
        fsg->function.bind      = fsg_bind;
        fsg->function.unbind    = fsg_unbind;
index 6316aa5b1c4947a6df2e08b4c45856dc77b94374..ad50a67c14656aa70f6804572486954f0e389887 100644 (file)
@@ -1145,7 +1145,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
        if (opts->id && !midi->id) {
                status = -ENOMEM;
                mutex_unlock(&opts->lock);
-               goto kstrdup_fail;
+               goto setup_fail;
        }
        midi->in_ports = opts->in_ports;
        midi->out_ports = opts->out_ports;
@@ -1164,8 +1164,6 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
 
        return &midi->func;
 
-kstrdup_fail:
-       f_midi_unregister_card(midi);
 setup_fail:
        for (--i; i >= 0; i--)
                kfree(midi->in_port[i]);
index 44173df272739543a6b3168323073dba45239760..357f63f47b42aba69d92e24346963645227d39e2 100644 (file)
@@ -1248,7 +1248,15 @@ static struct config_item_type printer_func_type = {
 
 static inline int gprinter_get_minor(void)
 {
-       return ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+       int ret;
+
+       ret = ida_simple_get(&printer_ida, 0, 0, GFP_KERNEL);
+       if (ret >= PRINTER_MINORS) {
+               ida_simple_remove(&printer_ida, ret);
+               ret = -ENODEV;
+       }
+
+       return ret;
 }
 
 static inline void gprinter_put_minor(int minor)
index 6d3eb8b00a488446db954334e80ac12eccf0d5cf..53186154725330d4c1f710e4829d4a8b25b614cd 100644 (file)
@@ -1162,14 +1162,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
                        factor = 1000;
                } else {
                        ep_desc = &hs_epin_desc;
-                       factor = 125;
+                       factor = 8000;
                }
 
                /* pre-compute some values for iso_complete() */
                uac2->p_framesize = opts->p_ssize *
                                    num_channels(opts->p_chmask);
                rate = opts->p_srate * uac2->p_framesize;
-               uac2->p_interval = (1 << (ep_desc->bInterval - 1)) * factor;
+               uac2->p_interval = factor / (1 << (ep_desc->bInterval - 1));
                uac2->p_pktsize = min_t(unsigned int, rate / uac2->p_interval,
                                        prm->max_psize);
 
index b04980cf6dc42108f4861e4dfa7285dd4fe56af9..1efa61265d8d49c5116027c8e3555ae70b9cc12c 100644 (file)
@@ -779,7 +779,7 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
        /* The current hw dequeue pointer */
        tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0));
        deq_ptr_64 = tmp_32;
-       tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(1));
+       tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0));
        deq_ptr_64 |= ((u64)tmp_32 << 32);
 
        /* we have the dma addr of next bd that will be fetched by hardware */
index e547ea7f56b13375095031a42d4c40757f64015e..1137e3384218c11e738b88067f01fd8ee4105f25 100644 (file)
@@ -1171,7 +1171,7 @@ static int fotg210_udc_probe(struct platform_device *pdev)
                          udc_name, fotg210);
        if (ret < 0) {
                pr_err("request_irq error (%d)\n", ret);
-               goto err_irq;
+               goto err_req;
        }
 
        ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);
@@ -1183,7 +1183,6 @@ static int fotg210_udc_probe(struct platform_device *pdev)
        return 0;
 
 err_add_udc:
-err_irq:
        free_irq(ires->start, fotg210);
 
 err_req:
index d32160d6463f5fd3ca16442cdb37f0f0289fb5dc..5da37c957b53ce34bd9820ebfd57b9f20a5815c4 100644 (file)
@@ -2167,7 +2167,7 @@ static int mv_udc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       udc->phy_regs = ioremap(r->start, resource_size(r));
+       udc->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
        if (udc->phy_regs == NULL) {
                dev_err(&pdev->dev, "failed to map phy I/O memory\n");
                return -EBUSY;
index d69c35558f6852beecd1bfc85acee35c26781ec8..89ed5e71a1991e0cd249c48b18bd04dd67bacf91 100644 (file)
@@ -60,13 +60,15 @@ static DEFINE_MUTEX(udc_lock);
 int usb_gadget_map_request(struct usb_gadget *gadget,
                struct usb_request *req, int is_in)
 {
+       struct device *dev = gadget->dev.parent;
+
        if (req->length == 0)
                return 0;
 
        if (req->num_sgs) {
                int     mapped;
 
-               mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
+               mapped = dma_map_sg(dev, req->sg, req->num_sgs,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
                if (mapped == 0) {
                        dev_err(&gadget->dev, "failed to map SGs\n");
@@ -75,11 +77,11 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
 
                req->num_mapped_sgs = mapped;
        } else {
-               req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
+               req->dma = dma_map_single(dev, req->buf, req->length,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
-               if (dma_mapping_error(&gadget->dev, req->dma)) {
-                       dev_err(&gadget->dev, "failed to map buffer\n");
+               if (dma_mapping_error(dev, req->dma)) {
+                       dev_err(dev, "failed to map buffer\n");
                        return -EFAULT;
                }
        }
@@ -95,12 +97,12 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget,
                return;
 
        if (req->num_mapped_sgs) {
-               dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
+               dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 
                req->num_mapped_sgs = 0;
        } else {
-               dma_unmap_single(&gadget->dev, req->dma, req->length,
+               dma_unmap_single(gadget->dev.parent, req->dma, req->length,
                                is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
        }
 }
@@ -321,6 +323,7 @@ err4:
 
 err3:
        put_device(&udc->dev);
+       device_del(&gadget->dev);
 
 err2:
        put_device(&gadget->dev);
index f7d561ed3c236290aa90334b90bd52cbfa9f7632..d029bbe9eb36a884fed45fd6f648bfca51199d65 100644 (file)
@@ -981,10 +981,6 @@ rescan_all:
                int                     completed, modified;
                __hc32                  *prev;
 
-               /* Is this ED already invisible to the hardware? */
-               if (ed->state == ED_IDLE)
-                       goto ed_idle;
-
                /* only take off EDs that the HC isn't using, accounting for
                 * frame counter wraps and EDs with partially retired TDs
                 */
@@ -1012,12 +1008,10 @@ skip_ed:
                }
 
                /* ED's now officially unlinked, hc doesn't see */
-               ed->state = ED_IDLE;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb();
                ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
-ed_idle:
 
                /* reentrancy:  if we drop the schedule lock, someone might
                 * have modified this list.  normally it's just prepending
@@ -1088,6 +1082,7 @@ rescan_this:
                if (list_empty(&ed->td_list)) {
                        *last = ed->ed_next;
                        ed->ed_next = NULL;
+                       ed->state = ED_IDLE;
                        list_del(&ed->in_use_list);
                } else if (ohci->rh_state == OHCI_RH_RUNNING) {
                        *last = ed->ed_next;
index e9a6eec39142584032f777aa6101c00604b5ccf5..cfcfadfc94fc25b8e10d788e59514c146d32ccc1 100644 (file)
@@ -58,7 +58,7 @@
 #define CCR_PM_CKRNEN    0x0002
 #define CCR_PM_USBPW1    0x0004
 #define CCR_PM_USBPW2    0x0008
-#define CCR_PM_USBPW3    0x0008
+#define CCR_PM_USBPW3    0x0010
 #define CCR_PM_PMEE      0x0100
 #define CCR_PM_PMES      0x8000
 
index e75c565feb53ef3022312c047268367de71ae059..78241b5550df877fb09189936867f7821e09d11a 100644 (file)
@@ -484,10 +484,13 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
        u32 pls = status_reg & PORT_PLS_MASK;
 
        /* resume state is a xHCI internal state.
-        * Do not report it to usb core.
+        * Do not report it to usb core, instead, pretend to be U3,
+        * thus usb core knows it's not ready for transfer
         */
-       if (pls == XDEV_RESUME)
+       if (pls == XDEV_RESUME) {
+               *status |= USB_SS_PORT_LS_U3;
                return;
+       }
 
        /* When the CAS bit is set then warm reset
         * should be performed on port
@@ -588,7 +591,14 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
                status |= USB_PORT_STAT_C_RESET << 16;
        /* USB3.0 only */
        if (hcd->speed == HCD_USB3) {
-               if ((raw_port_status & PORT_PLC))
+               /* Port link change with port in resume state should not be
+                * reported to usbcore, as this is an internal state to be
+                * handled by xhci driver. Reporting PLC to usbcore may
+                * cause usbcore clearing PLC first and port change event
+                * irq won't be generated.
+                */
+               if ((raw_port_status & PORT_PLC) &&
+                       (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME)
                        status |= USB_PORT_STAT_C_LINK_STATE << 16;
                if ((raw_port_status & PORT_WRC))
                        status |= USB_PORT_STAT_C_BH_RESET << 16;
@@ -1120,10 +1130,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
        spin_lock_irqsave(&xhci->lock, flags);
 
        if (hcd->self.root_hub->do_remote_wakeup) {
-               if (bus_state->resuming_ports) {
+               if (bus_state->resuming_ports ||        /* USB2 */
+                   bus_state->port_remote_wakeup) {    /* USB3 */
                        spin_unlock_irqrestore(&xhci->lock, flags);
-                       xhci_dbg(xhci, "suspend failed because "
-                                               "a port is resuming\n");
+                       xhci_dbg(xhci, "suspend failed because a port is resuming\n");
                        return -EBUSY;
                }
        }
index f8336408ef07c4354ad54c43e988b6b43272eea0..9a8c936cd42c18ef72a695d45c7e4ce2e893f8b0 100644 (file)
@@ -1427,10 +1427,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
                /* Attempt to use the ring cache */
                if (virt_dev->num_rings_cached == 0)
                        return -ENOMEM;
+               virt_dev->num_rings_cached--;
                virt_dev->eps[ep_index].new_ring =
                        virt_dev->ring_cache[virt_dev->num_rings_cached];
                virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
-               virt_dev->num_rings_cached--;
                xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
                                        1, type);
        }
@@ -1792,7 +1792,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        int size;
        int i, j, num_ports;
 
-       del_timer_sync(&xhci->cmd_timer);
+       if (timer_pending(&xhci->cmd_timer))
+               del_timer_sync(&xhci->cmd_timer);
 
        /* Free the Event Ring Segment Table and the actual Event Ring */
        size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
index 4a4cb1d91ac8465d5ff274f5ded1a62e299cf92f..5590eac2b22df26ea4150d7bb8a8e1eeb2406ae3 100644 (file)
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/acpi.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
 
+#define PORT2_SSIC_CONFIG_REG2 0x883c
+#define PROG_DONE              (1 << 30)
+#define SSIC_PORT_UNUSED       (1 << 31)
+
 /* Device for a quirk */
 #define PCI_VENDOR_ID_FRESCO_LOGIC     0x1b73
 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
@@ -176,20 +181,63 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
 }
 
 /*
+ * In some Intel xHCI controllers, in order to get D3 working,
+ * through a vendor specific SSIC CONFIG register at offset 0x883c,
+ * SSIC PORT need to be marked as "unused" before putting xHCI
+ * into D3. After D3 exit, the SSIC port need to be marked as "used".
+ * Without this change, xHCI might not enter D3 state.
  * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
  * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
  */
-static void xhci_pme_quirk(struct xhci_hcd *xhci)
+static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
 {
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        u32 val;
        void __iomem *reg;
 
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
+
+               reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
+
+               /* Notify SSIC that SSIC profile programming is not done */
+               val = readl(reg) & ~PROG_DONE;
+               writel(val, reg);
+
+               /* Mark SSIC port as unused(suspend) or used(resume) */
+               val = readl(reg);
+               if (suspend)
+                       val |= SSIC_PORT_UNUSED;
+               else
+                       val &= ~SSIC_PORT_UNUSED;
+               writel(val, reg);
+
+               /* Notify SSIC that SSIC profile programming is done */
+               val = readl(reg) | PROG_DONE;
+               writel(val, reg);
+               readl(reg);
+       }
+
        reg = (void __iomem *) xhci->cap_regs + 0x80a4;
        val = readl(reg);
        writel(val | BIT(28), reg);
        readl(reg);
 }
 
+#ifdef CONFIG_ACPI
+static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
+{
+       static const u8 intel_dsm_uuid[] = {
+               0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
+               0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
+       };
+       acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL);
+}
+#else
+       static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+#endif /* CONFIG_ACPI */
+
 /* called during probe() after chip reset completes */
 static int xhci_pci_setup(struct usb_hcd *hcd)
 {
@@ -263,6 +311,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                        HCC_MAX_PSA(xhci->hcc_params) >= 4)
                xhci->shared_hcd->can_do_streams = 1;
 
+       if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
+               xhci_pme_acpi_rtd3_enable(dev);
+
        /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
        pm_runtime_put_noidle(&dev->dev);
 
@@ -307,7 +358,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
                pdev->no_d3cold = true;
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
-               xhci_pme_quirk(xhci);
+               xhci_pme_quirk(hcd, true);
 
        return xhci_suspend(xhci, do_wakeup);
 }
@@ -340,7 +391,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
                usb_enable_intel_xhci_ports(pdev);
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
-               xhci_pme_quirk(xhci);
+               xhci_pme_quirk(hcd, false);
 
        retval = xhci_resume(xhci, hibernated);
        return retval;
index 94416ff7081071e3f32a682493e6a34bb8d359a8..32f4d564494a9f48cfebd328e61d3c281387d252 100644 (file)
@@ -82,7 +82,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
                return 0;
        /* offset in TRBs */
        segment_offset = trb - seg->trbs;
-       if (segment_offset > TRBS_PER_SEGMENT)
+       if (segment_offset >= TRBS_PER_SEGMENT)
                return 0;
        return seg->dma + (segment_offset * sizeof(*trb));
 }
@@ -1546,6 +1546,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
                usb_hcd_resume_root_hub(hcd);
        }
 
+       if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
+               bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+
        if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
                xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 
index 7da0d6043d33e13afa3ce4db45d5dfa54b4d3d22..526ebc0c7e720b9d766bcf6abf1bc65672e584bb 100644 (file)
@@ -3453,6 +3453,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
                        return -EINVAL;
        }
 
+       if (virt_dev->tt_info)
+               old_active_eps = virt_dev->tt_info->active_eps;
+
        if (virt_dev->udev != udev) {
                /* If the virt_dev and the udev does not match, this virt_dev
                 * may belong to another udev.
index 31e46cc55807a83a69f9e6e8ce9e89f176786215..ed2ebf647c380ebbdfe647544fb137283219cf87 100644 (file)
@@ -285,6 +285,7 @@ struct xhci_op_regs {
 #define XDEV_U0                (0x0 << 5)
 #define XDEV_U2                (0x2 << 5)
 #define XDEV_U3                (0x3 << 5)
+#define XDEV_INACTIVE  (0x6 << 5)
 #define XDEV_RESUME    (0xf << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER     (1 << 9)
index 30842bc195f57fced81ff6190f4758570ee77d3e..92d5f718659b7ebbeba0898428de681af18fdf2a 100644 (file)
@@ -275,9 +275,7 @@ static int musb_has_gadget(struct musb *musb)
 #ifdef CONFIG_USB_MUSB_HOST
        return 1;
 #else
-       if (musb->port_mode == MUSB_PORT_MODE_HOST)
-               return 1;
-       return musb->g.dev.driver != NULL;
+       return musb->port_mode == MUSB_PORT_MODE_HOST;
 #endif
 }
 
index 8f7cb068d29bab1eb1f9641e41cbe4da30e22489..3fcc0483a0811e8f7e2984aea1c4a11ce2da0951 100644 (file)
@@ -217,6 +217,9 @@ static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
 {
        unsigned int vbus_value;
 
+       if (!mxs_phy->regmap_anatop)
+               return false;
+
        if (mxs_phy->port_id == 0)
                regmap_read(mxs_phy->regmap_anatop,
                        ANADIG_USB1_VBUS_DET_STAT,
index ffd739e31bfc193b058628560e86ea6f9b96f375..eac7ccaa3c859cc3bae90e897fc071caa7168cfd 100644 (file)
@@ -187,6 +187,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */
        { USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */
        { USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */
+       { USB_DEVICE(0x2626, 0xEA60) }, /* Aruba Networks 7xxx USB Serial Console */
        { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
        { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
        { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
index 4f70df33975a4a9bf02d3945e8b2bb956b1e7cd6..78b4f64c6b00e457cef0bc65ed636a3e9fa8db42 100644 (file)
@@ -121,26 +121,26 @@ static DEFINE_SPINLOCK(release_lock);
 static const unsigned int dummy; /* for clarity in register access fns */
 
 enum mos_regs {
-       THR,              /* serial port regs */
-       RHR,
-       IER,
-       FCR,
-       ISR,
-       LCR,
-       MCR,
-       LSR,
-       MSR,
-       SPR,
-       DLL,
-       DLM,
-       DPR,              /* parallel port regs */
-       DSR,
-       DCR,
-       ECR,
-       SP1_REG,          /* device control regs */
-       SP2_REG,          /* serial port 2 (7720 only) */
-       PP_REG,
-       SP_CONTROL_REG,
+       MOS7720_THR,              /* serial port regs */
+       MOS7720_RHR,
+       MOS7720_IER,
+       MOS7720_FCR,
+       MOS7720_ISR,
+       MOS7720_LCR,
+       MOS7720_MCR,
+       MOS7720_LSR,
+       MOS7720_MSR,
+       MOS7720_SPR,
+       MOS7720_DLL,
+       MOS7720_DLM,
+       MOS7720_DPR,              /* parallel port regs */
+       MOS7720_DSR,
+       MOS7720_DCR,
+       MOS7720_ECR,
+       MOS7720_SP1_REG,          /* device control regs */
+       MOS7720_SP2_REG,          /* serial port 2 (7720 only) */
+       MOS7720_PP_REG,
+       MOS7720_SP_CONTROL_REG,
 };
 
 /*
@@ -150,26 +150,26 @@ enum mos_regs {
 static inline __u16 get_reg_index(enum mos_regs reg)
 {
        static const __u16 mos7715_index_lookup_table[] = {
-               0x00,           /* THR */
-               0x00,           /* RHR */
-               0x01,           /* IER */
-               0x02,           /* FCR */
-               0x02,           /* ISR */
-               0x03,           /* LCR */
-               0x04,           /* MCR */
-               0x05,           /* LSR */
-               0x06,           /* MSR */
-               0x07,           /* SPR */
-               0x00,           /* DLL */
-               0x01,           /* DLM */
-               0x00,           /* DPR */
-               0x01,           /* DSR */
-               0x02,           /* DCR */
-               0x0a,           /* ECR */
-               0x01,           /* SP1_REG */
-               0x02,           /* SP2_REG (7720 only) */
-               0x04,           /* PP_REG (7715 only) */
-               0x08,           /* SP_CONTROL_REG */
+               0x00,           /* MOS7720_THR */
+               0x00,           /* MOS7720_RHR */
+               0x01,           /* MOS7720_IER */
+               0x02,           /* MOS7720_FCR */
+               0x02,           /* MOS7720_ISR */
+               0x03,           /* MOS7720_LCR */
+               0x04,           /* MOS7720_MCR */
+               0x05,           /* MOS7720_LSR */
+               0x06,           /* MOS7720_MSR */
+               0x07,           /* MOS7720_SPR */
+               0x00,           /* MOS7720_DLL */
+               0x01,           /* MOS7720_DLM */
+               0x00,           /* MOS7720_DPR */
+               0x01,           /* MOS7720_DSR */
+               0x02,           /* MOS7720_DCR */
+               0x0a,           /* MOS7720_ECR */
+               0x01,           /* MOS7720_SP1_REG */
+               0x02,           /* MOS7720_SP2_REG (7720 only) */
+               0x04,           /* MOS7720_PP_REG (7715 only) */
+               0x08,           /* MOS7720_SP_CONTROL_REG */
        };
        return mos7715_index_lookup_table[reg];
 }
@@ -181,10 +181,10 @@ static inline __u16 get_reg_index(enum mos_regs reg)
 static inline __u16 get_reg_value(enum mos_regs reg,
                                  unsigned int serial_portnum)
 {
-       if (reg >= SP1_REG)           /* control reg */
+       if (reg >= MOS7720_SP1_REG)     /* control reg */
                return 0x0000;
 
-       else if (reg >= DPR)          /* parallel port reg (7715 only) */
+       else if (reg >= MOS7720_DPR)    /* parallel port reg (7715 only) */
                return 0x0100;
 
        else                          /* serial port reg */
@@ -252,7 +252,8 @@ static inline int mos7715_change_mode(struct mos7715_parport *mos_parport,
                                      enum mos7715_pp_modes mode)
 {
        mos_parport->shadowECR = mode;
-       write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
+                     mos_parport->shadowECR);
        return 0;
 }
 
@@ -486,7 +487,7 @@ static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
        if (parport_prologue(pp) < 0)
                return;
        mos7715_change_mode(mos_parport, SPP);
-       write_mos_reg(mos_parport->serial, dummy, DPR, (__u8)d);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_DPR, (__u8)d);
        parport_epilogue(pp);
 }
 
@@ -497,7 +498,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp)
 
        if (parport_prologue(pp) < 0)
                return 0;
-       read_mos_reg(mos_parport->serial, dummy, DPR, &d);
+       read_mos_reg(mos_parport->serial, dummy, MOS7720_DPR, &d);
        parport_epilogue(pp);
        return d;
 }
@@ -510,7 +511,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
        if (parport_prologue(pp) < 0)
                return;
        data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
-       write_mos_reg(mos_parport->serial, dummy, DCR, data);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR, data);
        mos_parport->shadowDCR = data;
        parport_epilogue(pp);
 }
@@ -543,7 +544,8 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp,
        if (parport_prologue(pp) < 0)
                return 0;
        mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val;
-       write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+                     mos_parport->shadowDCR);
        dcr = mos_parport->shadowDCR & 0x0f;
        parport_epilogue(pp);
        return dcr;
@@ -581,7 +583,8 @@ static void parport_mos7715_data_forward(struct parport *pp)
                return;
        mos7715_change_mode(mos_parport, PS2);
        mos_parport->shadowDCR &=  ~0x20;
-       write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+                     mos_parport->shadowDCR);
        parport_epilogue(pp);
 }
 
@@ -593,7 +596,8 @@ static void parport_mos7715_data_reverse(struct parport *pp)
                return;
        mos7715_change_mode(mos_parport, PS2);
        mos_parport->shadowDCR |= 0x20;
-       write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+                     mos_parport->shadowDCR);
        parport_epilogue(pp);
 }
 
@@ -633,8 +637,10 @@ static void parport_mos7715_restore_state(struct parport *pp,
                spin_unlock(&release_lock);
                return;
        }
-       write_parport_reg_nonblock(mos_parport, DCR, mos_parport->shadowDCR);
-       write_parport_reg_nonblock(mos_parport, ECR, mos_parport->shadowECR);
+       write_parport_reg_nonblock(mos_parport, MOS7720_DCR,
+                                  mos_parport->shadowDCR);
+       write_parport_reg_nonblock(mos_parport, MOS7720_ECR,
+                                  mos_parport->shadowECR);
        spin_unlock(&release_lock);
 }
 
@@ -714,14 +720,16 @@ static int mos7715_parport_init(struct usb_serial *serial)
        init_completion(&mos_parport->syncmsg_compl);
 
        /* cycle parallel port reset bit */
-       write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x80);
-       write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x00);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_PP_REG, (__u8)0x80);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_PP_REG, (__u8)0x00);
 
        /* initialize device registers */
        mos_parport->shadowDCR = DCR_INIT_VAL;
-       write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR,
+                     mos_parport->shadowDCR);
        mos_parport->shadowECR = ECR_INIT_VAL;
-       write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR);
+       write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR,
+                     mos_parport->shadowECR);
 
        /* register with parport core */
        mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE,
@@ -1033,45 +1041,49 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
         /* Initialize MCS7720 -- Write Init values to corresponding Registers
          *
          * Register Index
-         * 0 : THR/RHR
-         * 1 : IER
-         * 2 : FCR
-         * 3 : LCR
-         * 4 : MCR
-         * 5 : LSR
-         * 6 : MSR
-         * 7 : SPR
+         * 0 : MOS7720_THR/MOS7720_RHR
+         * 1 : MOS7720_IER
+         * 2 : MOS7720_FCR
+         * 3 : MOS7720_LCR
+         * 4 : MOS7720_MCR
+         * 5 : MOS7720_LSR
+         * 6 : MOS7720_MSR
+         * 7 : MOS7720_SPR
          *
          * 0x08 : SP1/2 Control Reg
          */
        port_number = port->port_number;
-       read_mos_reg(serial, port_number, LSR, &data);
+       read_mos_reg(serial, port_number, MOS7720_LSR, &data);
 
        dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data);
 
-       write_mos_reg(serial, dummy, SP1_REG, 0x02);
-       write_mos_reg(serial, dummy, SP2_REG, 0x02);
+       write_mos_reg(serial, dummy, MOS7720_SP1_REG, 0x02);
+       write_mos_reg(serial, dummy, MOS7720_SP2_REG, 0x02);
 
-       write_mos_reg(serial, port_number, IER, 0x00);
-       write_mos_reg(serial, port_number, FCR, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
 
-       write_mos_reg(serial, port_number, FCR, 0xcf);
+       write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
        mos7720_port->shadowLCR = 0x03;
-       write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+       write_mos_reg(serial, port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
        mos7720_port->shadowMCR = 0x0b;
-       write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+       write_mos_reg(serial, port_number, MOS7720_MCR,
+                     mos7720_port->shadowMCR);
 
-       write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00);
-       read_mos_reg(serial, dummy, SP_CONTROL_REG, &data);
+       write_mos_reg(serial, port_number, MOS7720_SP_CONTROL_REG, 0x00);
+       read_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, &data);
        data = data | (port->port_number + 1);
-       write_mos_reg(serial, dummy, SP_CONTROL_REG, data);
+       write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, data);
        mos7720_port->shadowLCR = 0x83;
-       write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
-       write_mos_reg(serial, port_number, THR, 0x0c);
-       write_mos_reg(serial, port_number, IER, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
+       write_mos_reg(serial, port_number, MOS7720_THR, 0x0c);
+       write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
        mos7720_port->shadowLCR = 0x03;
-       write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
-       write_mos_reg(serial, port_number, IER, 0x0c);
+       write_mos_reg(serial, port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
+       write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
 
        response = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (response)
@@ -1144,8 +1156,8 @@ static void mos7720_close(struct usb_serial_port *port)
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
 
-       write_mos_reg(serial, port->port_number, MCR, 0x00);
-       write_mos_reg(serial, port->port_number, IER, 0x00);
+       write_mos_reg(serial, port->port_number, MOS7720_MCR, 0x00);
+       write_mos_reg(serial, port->port_number, MOS7720_IER, 0x00);
 
        mos7720_port->open = 0;
 }
@@ -1169,7 +1181,8 @@ static void mos7720_break(struct tty_struct *tty, int break_state)
                data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
 
        mos7720_port->shadowLCR  = data;
-       write_mos_reg(serial, port->port_number, LCR, mos7720_port->shadowLCR);
+       write_mos_reg(serial, port->port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
 }
 
 /*
@@ -1297,7 +1310,7 @@ static void mos7720_throttle(struct tty_struct *tty)
        /* if we are implementing RTS/CTS, toggle that line */
        if (tty->termios.c_cflag & CRTSCTS) {
                mos7720_port->shadowMCR &= ~UART_MCR_RTS;
-               write_mos_reg(port->serial, port->port_number, MCR,
+               write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
                              mos7720_port->shadowMCR);
        }
 }
@@ -1327,7 +1340,7 @@ static void mos7720_unthrottle(struct tty_struct *tty)
        /* if we are implementing RTS/CTS, toggle that line */
        if (tty->termios.c_cflag & CRTSCTS) {
                mos7720_port->shadowMCR |= UART_MCR_RTS;
-               write_mos_reg(port->serial, port->port_number, MCR,
+               write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
                              mos7720_port->shadowMCR);
        }
 }
@@ -1352,35 +1365,39 @@ static int set_higher_rates(struct moschip_port *mos7720_port,
        dev_dbg(&port->dev, "Sending Setting Commands ..........\n");
        port_number = port->port_number;
 
-       write_mos_reg(serial, port_number, IER, 0x00);
-       write_mos_reg(serial, port_number, FCR, 0x00);
-       write_mos_reg(serial, port_number, FCR, 0xcf);
+       write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
        mos7720_port->shadowMCR = 0x0b;
-       write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
-       write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_MCR,
+                     mos7720_port->shadowMCR);
+       write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, 0x00);
 
        /***********************************************
         *              Set for higher rates           *
         ***********************************************/
        /* writing baud rate verbatum into uart clock field clearly not right */
        if (port_number == 0)
-               sp_reg = SP1_REG;
+               sp_reg = MOS7720_SP1_REG;
        else
-               sp_reg = SP2_REG;
+               sp_reg = MOS7720_SP2_REG;
        write_mos_reg(serial, dummy, sp_reg, baud * 0x10);
-       write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x03);
+       write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG, 0x03);
        mos7720_port->shadowMCR = 0x2b;
-       write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+       write_mos_reg(serial, port_number, MOS7720_MCR,
+                     mos7720_port->shadowMCR);
 
        /***********************************************
         *              Set DLL/DLM
         ***********************************************/
        mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
-       write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
-       write_mos_reg(serial, port_number, DLL, 0x01);
-       write_mos_reg(serial, port_number, DLM, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
+       write_mos_reg(serial, port_number, MOS7720_DLL, 0x01);
+       write_mos_reg(serial, port_number, MOS7720_DLM, 0x00);
        mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
-       write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+       write_mos_reg(serial, port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
 
        return 0;
 }
@@ -1488,15 +1505,16 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
 
        /* Enable access to divisor latch */
        mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB;
-       write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR);
+       write_mos_reg(serial, number, MOS7720_LCR, mos7720_port->shadowLCR);
 
        /* Write the divisor */
-       write_mos_reg(serial, number, DLL, (__u8)(divisor & 0xff));
-       write_mos_reg(serial, number, DLM, (__u8)((divisor & 0xff00) >> 8));
+       write_mos_reg(serial, number, MOS7720_DLL, (__u8)(divisor & 0xff));
+       write_mos_reg(serial, number, MOS7720_DLM,
+                     (__u8)((divisor & 0xff00) >> 8));
 
        /* Disable access to divisor latch */
        mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
-       write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR);
+       write_mos_reg(serial, number, MOS7720_LCR, mos7720_port->shadowLCR);
 
        return status;
 }
@@ -1600,14 +1618,16 @@ static void change_port_settings(struct tty_struct *tty,
 
 
        /* Disable Interrupts */
-       write_mos_reg(serial, port_number, IER, 0x00);
-       write_mos_reg(serial, port_number, FCR, 0x00);
-       write_mos_reg(serial, port_number, FCR, 0xcf);
+       write_mos_reg(serial, port_number, MOS7720_IER, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_FCR, 0x00);
+       write_mos_reg(serial, port_number, MOS7720_FCR, 0xcf);
 
        /* Send the updated LCR value to the mos7720 */
-       write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
+       write_mos_reg(serial, port_number, MOS7720_LCR,
+                     mos7720_port->shadowLCR);
        mos7720_port->shadowMCR = 0x0b;
-       write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+       write_mos_reg(serial, port_number, MOS7720_MCR,
+                     mos7720_port->shadowMCR);
 
        /* set up the MCR register and send it to the mos7720 */
        mos7720_port->shadowMCR = UART_MCR_OUT2;
@@ -1619,14 +1639,17 @@ static void change_port_settings(struct tty_struct *tty,
                /* To set hardware flow control to the specified *
                 * serial port, in SP1/2_CONTROL_REG             */
                if (port_number)
-                       write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01);
+                       write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG,
+                                     0x01);
                else
-                       write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02);
+                       write_mos_reg(serial, dummy, MOS7720_SP_CONTROL_REG,
+                                     0x02);
 
        } else
                mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
 
-       write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR);
+       write_mos_reg(serial, port_number, MOS7720_MCR,
+                     mos7720_port->shadowMCR);
 
        /* Determine divisor based on baud rate */
        baud = tty_get_baud_rate(tty);
@@ -1639,7 +1662,7 @@ static void change_port_settings(struct tty_struct *tty,
        if (baud >= 230400) {
                set_higher_rates(mos7720_port, baud);
                /* Enable Interrupts */
-               write_mos_reg(serial, port_number, IER, 0x0c);
+               write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
                return;
        }
 
@@ -1650,7 +1673,7 @@ static void change_port_settings(struct tty_struct *tty,
        if (cflag & CBAUD)
                tty_encode_baud_rate(tty, baud, baud);
        /* Enable Interrupts */
-       write_mos_reg(serial, port_number, IER, 0x0c);
+       write_mos_reg(serial, port_number, MOS7720_IER, 0x0c);
 
        if (port->read_urb->status != -EINPROGRESS) {
                status = usb_submit_urb(port->read_urb, GFP_KERNEL);
@@ -1725,7 +1748,7 @@ static int get_lsr_info(struct tty_struct *tty,
 
        count = mos7720_chars_in_buffer(tty);
        if (count == 0) {
-               read_mos_reg(port->serial, port_number, LSR, &data);
+               read_mos_reg(port->serial, port_number, MOS7720_LSR, &data);
                if ((data & (UART_LSR_TEMT | UART_LSR_THRE))
                                        == (UART_LSR_TEMT | UART_LSR_THRE)) {
                        dev_dbg(&port->dev, "%s -- Empty\n", __func__);
@@ -1782,7 +1805,7 @@ static int mos7720_tiocmset(struct tty_struct *tty,
                mcr &= ~UART_MCR_LOOP;
 
        mos7720_port->shadowMCR = mcr;
-       write_mos_reg(port->serial, port->port_number, MCR,
+       write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
                      mos7720_port->shadowMCR);
 
        return 0;
@@ -1827,7 +1850,7 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
        }
 
        mos7720_port->shadowMCR = mcr;
-       write_mos_reg(port->serial, port->port_number, MCR,
+       write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
                      mos7720_port->shadowMCR);
 
        return 0;
@@ -1942,7 +1965,7 @@ static int mos7720_startup(struct usb_serial *serial)
        }
 #endif
        /* LSR For Port 1 */
-       read_mos_reg(serial, 0, LSR, &data);
+       read_mos_reg(serial, 0, MOS7720_LSR, &data);
        dev_dbg(&dev->dev, "LSR:%x\n", data);
 
        return 0;
index f0c0c53359ad68d5f1bc4cc5ec67ac1e152f4b99..876423b8892c96f80930fa7a103f36370e519dfe 100644 (file)
@@ -1099,6 +1099,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
        { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff),
          .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */
+       { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x9041, 0xff),
+         .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC7305/MC7355 */
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
@@ -1765,6 +1767,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
+       { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },                /* OLICARD300 - MT6225 */
        { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
        { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
        { } /* Terminating entry */
index 9c63897b3a564012ea63f99b9e5e73bc48b93d36..d156545728c2ab5b8bb81cf7537aa8a60805c08a 100644 (file)
@@ -145,7 +145,6 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x1199, 0x901c)},   /* Sierra Wireless EM7700 */
        {DEVICE_SWI(0x1199, 0x901f)},   /* Sierra Wireless EM7355 */
        {DEVICE_SWI(0x1199, 0x9040)},   /* Sierra Wireless Modem */
-       {DEVICE_SWI(0x1199, 0x9041)},   /* Sierra Wireless MC7305/MC7355 */
        {DEVICE_SWI(0x1199, 0x9051)},   /* Netgear AirCard 340U */
        {DEVICE_SWI(0x1199, 0x9053)},   /* Sierra Wireless Modem */
        {DEVICE_SWI(0x1199, 0x9054)},   /* Sierra Wireless Modem */
@@ -158,6 +157,7 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x413c, 0x81a4)},   /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a8)},   /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a9)},   /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {DEVICE_SWI(0x413c, 0x81b1)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
 
        /* Huawei devices */
        {DEVICE_HWI(0x03f0, 0x581d)},   /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
index 46179a0828ebcbad9a78c11dad8044edff27664a..07d1ecd564f79d9c51798f6941b1295d794d468c 100644 (file)
@@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF),
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
+       { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */
        /* AT&T Direct IP LTE modems */
        { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF),
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
index 529066bbc7e81be1bb67e398f58425febef6a8eb..46f1f13b41f1459264e292d36087962f1a666b6f 100644 (file)
@@ -1306,6 +1306,7 @@ static void __exit usb_serial_exit(void)
        tty_unregister_driver(usb_serial_tty_driver);
        put_tty_driver(usb_serial_tty_driver);
        bus_unregister(&usb_serial_bus_type);
+       idr_destroy(&serial_minors);
 }
 
 
index caf188800c679e7f24fc329903848a8c1f64d41a..6b2479123de7762f7145c93fdcd58efb11f51093 100644 (file)
@@ -2065,6 +2065,18 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_READ_DISC_INFO ),
 
+/* Reported by Oliver Neukum <oneukum@suse.com>
+ * This device morphes spontaneously into another device if the access
+ * pattern of Windows isn't followed. Thus writable media would be dirty
+ * if the initial instance is used. So the device is limited to its
+ * virtual CD.
+ * And yes, the concept that BCD goes up to 9 is not heeded */
+UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff,
+               "ZTE,Incorporated",
+               "ZTE WCDMA Technologies MSM",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
+
 /* Reported by Sven Geggus <sven-usbst@geggus.net>
  * This encrypted pen drive returns bogus data for the initial READ(10).
  */
@@ -2074,6 +2086,17 @@ UNUSUAL_DEV(  0x1b1c, 0x1ab5, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_INITIAL_READ10 ),
 
+/* Reported by Hans de Goede <hdegoede@redhat.com>
+ * These are mini projectors using USB for both power and video data transport
+ * The usb-storage interface is a virtual windows driver CD, which the gm12u320
+ * driver automatically converts into framebuffer & kms dri device nodes.
+ */
+UNUSUAL_DEV( 0x1de1, 0xc102, 0x0000, 0xffff,
+               "Grain-media Technology Corp.",
+               "USB3.0 Device GM12U320",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_DEVICE ),
+
 /* Patch by Richard Schütz <r.schtz@t-online.de>
  * This external hard drive enclosure uses a JMicron chip which
  * needs the US_FL_IGNORE_RESIDUE flag to work properly. */
index 2fb29dfeffbd7fa70a8a881f025d73ffd50b0b25..563c510f285c47d2a7362a4da8729fdc38e1dee0 100644 (file)
@@ -689,6 +689,23 @@ struct vfio_device *vfio_device_get_from_dev(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(vfio_device_get_from_dev);
 
+static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group,
+                                                    char *buf)
+{
+       struct vfio_device *device;
+
+       mutex_lock(&group->device_lock);
+       list_for_each_entry(device, &group->device_list, group_next) {
+               if (!strcmp(dev_name(device->dev), buf)) {
+                       vfio_device_get(device);
+                       break;
+               }
+       }
+       mutex_unlock(&group->device_lock);
+
+       return device;
+}
+
 /*
  * Caller must hold a reference to the vfio_device
  */
@@ -1198,53 +1215,53 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
 {
        struct vfio_device *device;
        struct file *filep;
-       int ret = -ENODEV;
+       int ret;
 
        if (0 == atomic_read(&group->container_users) ||
            !group->container->iommu_driver || !vfio_group_viable(group))
                return -EINVAL;
 
-       mutex_lock(&group->device_lock);
-       list_for_each_entry(device, &group->device_list, group_next) {
-               if (strcmp(dev_name(device->dev), buf))
-                       continue;
+       device = vfio_device_get_from_name(group, buf);
+       if (!device)
+               return -ENODEV;
 
-               ret = device->ops->open(device->device_data);
-               if (ret)
-                       break;
-               /*
-                * We can't use anon_inode_getfd() because we need to modify
-                * the f_mode flags directly to allow more than just ioctls
-                */
-               ret = get_unused_fd_flags(O_CLOEXEC);
-               if (ret < 0) {
-                       device->ops->release(device->device_data);
-                       break;
-               }
+       ret = device->ops->open(device->device_data);
+       if (ret) {
+               vfio_device_put(device);
+               return ret;
+       }
 
-               filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
-                                          device, O_RDWR);
-               if (IS_ERR(filep)) {
-                       put_unused_fd(ret);
-                       ret = PTR_ERR(filep);
-                       device->ops->release(device->device_data);
-                       break;
-               }
+       /*
+        * We can't use anon_inode_getfd() because we need to modify
+        * the f_mode flags directly to allow more than just ioctls
+        */
+       ret = get_unused_fd_flags(O_CLOEXEC);
+       if (ret < 0) {
+               device->ops->release(device->device_data);
+               vfio_device_put(device);
+               return ret;
+       }
 
-               /*
-                * TODO: add an anon_inode interface to do this.
-                * Appears to be missing by lack of need rather than
-                * explicitly prevented.  Now there's need.
-                */
-               filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+       filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
+                                  device, O_RDWR);
+       if (IS_ERR(filep)) {
+               put_unused_fd(ret);
+               ret = PTR_ERR(filep);
+               device->ops->release(device->device_data);
+               vfio_device_put(device);
+               return ret;
+       }
+
+       /*
+        * TODO: add an anon_inode interface to do this.
+        * Appears to be missing by lack of need rather than
+        * explicitly prevented.  Now there's need.
+        */
+       filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
 
-               vfio_device_get(device);
-               atomic_inc(&group->container_users);
+       atomic_inc(&group->container_users);
 
-               fd_install(ret, filep);
-               break;
-       }
-       mutex_unlock(&group->device_lock);
+       fd_install(ret, filep);
 
        return ret;
 }
index 9e8e004bb1c38d809c2af43b9d42c053db3a41a2..eec2f11809ff2463d2a714224925af9c679fead1 100644 (file)
 #include <linux/file.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/kthread.h>
 #include <linux/cgroup.h>
 #include <linux/module.h>
+#include <linux/sort.h>
 
 #include "vhost.h"
 
+static ushort max_mem_regions = 64;
+module_param(max_mem_regions, ushort, 0444);
+MODULE_PARM_DESC(max_mem_regions,
+       "Maximum number of memory regions in memory map. (default: 64)");
+
 enum {
-       VHOST_MEMORY_MAX_NREGIONS = 64,
        VHOST_MEMORY_F_LOG = 0x1,
 };
 
@@ -543,7 +549,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
                fput(dev->log_file);
        dev->log_file = NULL;
        /* No one will access memory at this point */
-       kfree(dev->memory);
+       kvfree(dev->memory);
        dev->memory = NULL;
        WARN_ON(!list_empty(&dev->work_list));
        if (dev->worker) {
@@ -663,6 +669,25 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
+static int vhost_memory_reg_sort_cmp(const void *p1, const void *p2)
+{
+       const struct vhost_memory_region *r1 = p1, *r2 = p2;
+       if (r1->guest_phys_addr < r2->guest_phys_addr)
+               return 1;
+       if (r1->guest_phys_addr > r2->guest_phys_addr)
+               return -1;
+       return 0;
+}
+
+static void *vhost_kvzalloc(unsigned long size)
+{
+       void *n = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+
+       if (!n)
+               n = vzalloc(size);
+       return n;
+}
+
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
 {
        struct vhost_memory mem, *newmem, *oldmem;
@@ -673,21 +698,23 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                return -EFAULT;
        if (mem.padding)
                return -EOPNOTSUPP;
-       if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+       if (mem.nregions > max_mem_regions)
                return -E2BIG;
-       newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+       newmem = vhost_kvzalloc(size + mem.nregions * sizeof(*m->regions));
        if (!newmem)
                return -ENOMEM;
 
        memcpy(newmem, &mem, size);
        if (copy_from_user(newmem->regions, m->regions,
                           mem.nregions * sizeof *m->regions)) {
-               kfree(newmem);
+               kvfree(newmem);
                return -EFAULT;
        }
+       sort(newmem->regions, newmem->nregions, sizeof(*newmem->regions),
+               vhost_memory_reg_sort_cmp, NULL);
 
        if (!memory_access_ok(d, newmem, 0)) {
-               kfree(newmem);
+               kvfree(newmem);
                return -EFAULT;
        }
        oldmem = d->memory;
@@ -699,7 +726,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                d->vqs[i]->memory = newmem;
                mutex_unlock(&d->vqs[i]->mutex);
        }
-       kfree(oldmem);
+       kvfree(oldmem);
        return 0;
 }
 
@@ -965,6 +992,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp)
                }
                if (eventfp != d->log_file) {
                        filep = d->log_file;
+                       d->log_file = eventfp;
                        ctx = d->log_ctx;
                        d->log_ctx = eventfp ?
                                eventfd_ctx_fileget(eventfp) : NULL;
@@ -992,17 +1020,22 @@ EXPORT_SYMBOL_GPL(vhost_dev_ioctl);
 static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
                                                     __u64 addr, __u32 len)
 {
-       struct vhost_memory_region *reg;
-       int i;
+       const struct vhost_memory_region *reg;
+       int start = 0, end = mem->nregions;
 
-       /* linear search is not brilliant, but we really have on the order of 6
-        * regions in practice */
-       for (i = 0; i < mem->nregions; ++i) {
-               reg = mem->regions + i;
-               if (reg->guest_phys_addr <= addr &&
-                   reg->guest_phys_addr + reg->memory_size - 1 >= addr)
-                       return reg;
+       while (start < end) {
+               int slot = start + (end - start) / 2;
+               reg = mem->regions + slot;
+               if (addr >= reg->guest_phys_addr)
+                       end = slot;
+               else
+                       start = slot + 1;
        }
+
+       reg = mem->regions + start;
+       if (addr >= reg->guest_phys_addr &&
+               reg->guest_phys_addr + reg->memory_size > addr)
+               return reg;
        return NULL;
 }
 
index 658c34bb9076f813058dfb03a47907ca48c6eb0a..1aaf89300621abc811f57f549c25b9a540a21d99 100644 (file)
@@ -1306,10 +1306,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
        int y;
        int c = scr_readw((u16 *) vc->vc_pos);
 
+       ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+
        if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
                return;
 
-       ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
        if (vc->vc_cursor_type & 0x10)
                fbcon_del_cursor_timer(info);
        else
index 2d98de535e0f7374804474c58de752ffb2848aa4..f888561568d91735a3a765a772630e8b2be0a54a 100644 (file)
@@ -298,7 +298,7 @@ config FB_ARMCLCD
 
 # Helper logic selected only by the ARM Versatile platform family.
 config PLAT_VERSATILE_CLCD
-       def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+       def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR
        depends on ARM
        depends on FB_ARMCLCD && FB=y
 
index 928ee639c0c19ba3a2346737c41b44f38e82c0b5..bf407b6ba15ca0002166a0704124eeda0fb2052e 100644 (file)
@@ -60,6 +60,8 @@ omapdss_of_get_next_port(const struct device_node *parent,
                        }
                        prev = port;
                } while (of_node_cmp(port->name, "port") != 0);
+
+               of_node_put(ports);
        }
 
        return port;
@@ -94,7 +96,7 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port)
        if (!port)
                return NULL;
 
-       np = of_get_next_parent(port);
+       np = of_get_parent(port);
 
        for (i = 0; i < 2 && np; ++i) {
                struct property *prop;
index 86bd457d039d2ad9a85e82d3f26a3630e3134da7..50bce45e7f3d47d78163058eff366b32d4f56180 100644 (file)
@@ -653,7 +653,7 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
                goto err_free_dma;
        }
 
-       ret = clk_enable(priv->clk);
+       ret = clk_prepare_enable(priv->clk);
        if (ret < 0) {
                dev_err(dev, "failed to enable clock\n");
                goto err_misc_deregister;
@@ -685,7 +685,7 @@ err_misc_deregister:
        misc_deregister(&priv->misc_dev);
 
 err_disable_clk:
-       clk_disable(priv->clk);
+       clk_disable_unprepare(priv->clk);
 
        return ret;
 }
index 86621fabbb8b3105a9b8e404e6c18b2f3830347d..735355b0e0233529ca8ed1fbbf4df40dec867bb9 100644 (file)
@@ -121,6 +121,7 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
 #define REG_3          0x0004a0
 #define REG_4          0x000600
 #define REG_6          0x000800
+#define REG_7          0x000804
 #define REG_8          0x000820
 #define REG_9          0x000a04
 #define REG_10         0x018000
@@ -135,6 +136,8 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
 #define REG_21         0x200218
 #define REG_22         0x0005a0
 #define REG_23         0x0005c0
+#define REG_24         0x000808
+#define REG_25         0x000b00
 #define REG_26         0x200118
 #define REG_27         0x200308
 #define REG_32         0x21003c
@@ -429,6 +432,9 @@ ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
 #define SET_LENXY_START_RECFILL(fb, lenxy) \
        WRITE_WORD(lenxy, fb, REG_9)
 
+#define SETUP_COPYAREA(fb) \
+       WRITE_BYTE(0, fb, REG_16b1)
+
 static void
 HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
 {
@@ -1004,6 +1010,36 @@ stifb_blank(int blank_mode, struct fb_info *info)
        return 0;
 }
 
+static void
+stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+       struct stifb_info *fb = container_of(info, struct stifb_info, info);
+
+       SETUP_COPYAREA(fb);
+
+       SETUP_HW(fb);
+       if (fb->info.var.bits_per_pixel == 32) {
+               WRITE_WORD(0xBBA0A000, fb, REG_10);
+
+               NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
+       } else {
+               WRITE_WORD(fb->id == S9000_ID_HCRX ? 0x13a02000 : 0x13a01000, fb, REG_10);
+
+               NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xff);
+       }
+
+       NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
+               IBOvals(RopSrc, MaskAddrOffset(0),
+               BitmapExtent08, StaticReg(1),
+               DataDynamic, MaskOtc, BGx(0), FGx(0)));
+
+       WRITE_WORD(((area->sx << 16) | area->sy), fb, REG_24);
+       WRITE_WORD(((area->width << 16) | area->height), fb, REG_7);
+       WRITE_WORD(((area->dx << 16) | area->dy), fb, REG_25);
+
+       SETUP_FB(fb);
+}
+
 static void __init
 stifb_init_display(struct stifb_info *fb)
 {
@@ -1069,7 +1105,7 @@ static struct fb_ops stifb_ops = {
        .fb_setcolreg   = stifb_setcolreg,
        .fb_blank       = stifb_blank,
        .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
+       .fb_copyarea    = stifb_copyarea,
        .fb_imageblit   = cfb_imageblit,
 };
 
@@ -1258,7 +1294,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
        info->fbops = &stifb_ops;
        info->screen_base = ioremap_nocache(REGION_BASE(fb,1), fix->smem_len);
        info->screen_size = fix->smem_len;
-       info->flags = FBINFO_DEFAULT;
+       info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA;
        info->pseudo_palette = &fb->pseudo_palette;
 
        /* This has to be done !!! */
index 111c2d1911d32ea38e86b11c0af753133ccfab05..b5102aa6090d111e25727f78422c8cbc183f086a 100644 (file)
@@ -44,11 +44,9 @@ int of_get_videomode(struct device_node *np, struct videomode *vm,
                index = disp->native_mode;
 
        ret = videomode_from_timings(disp, vm, index);
-       if (ret)
-               return ret;
 
        display_timings_release(disp);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(of_get_videomode);
index 60e2a16775637b778a8faeb8f2b3f84810a88716..c96944b59856c10c7d28c189b5ff86dbe4b3c932 100644 (file)
@@ -313,6 +313,7 @@ err_init_vq:
 static void virtinput_remove(struct virtio_device *vdev)
 {
        struct virtio_input *vi = vdev->priv;
+       void *buf;
        unsigned long flags;
 
        spin_lock_irqsave(&vi->lock, flags);
@@ -320,6 +321,9 @@ static void virtinput_remove(struct virtio_device *vdev)
        spin_unlock_irqrestore(&vi->lock, flags);
 
        input_unregister_device(vi->idev);
+       vdev->config->reset(vdev);
+       while ((buf = virtqueue_detach_unused_buf(vi->sts)) != NULL)
+               kfree(buf);
        vdev->config->del_vqs(vdev);
        kfree(vi);
 }
index c1b03f4235b99807d479672abdc6da0243107837..4e7fec36f5c36d55edd220469cac43c2d56c4840 100644 (file)
@@ -4,7 +4,7 @@
  * Watchdog driver for ARM SP805 watchdog module
  *
  * Copyright (C) 2010 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2 or later. This program is licensed "as is" without any
@@ -303,6 +303,6 @@ static struct amba_driver sp805_wdt_driver = {
 
 module_amba_driver(sp805_wdt_driver);
 
-MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
+MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
 MODULE_DESCRIPTION("ARM SP805 Watchdog Driver");
 MODULE_LICENSE("GPL");
index fd933695f2328f29c2493ee751f22230ec68cbb1..bf4a23c7c5918f6849e764a8376c3608cc591933 100644 (file)
@@ -472,7 +472,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
 }
 
 /*
- * We avoid multiple worker processes conflicting via the balloon mutex.
+ * As this is a work item it is guaranteed to run as a single instance only.
  * We may of course race updates of the target counts (which are protected
  * by the balloon lock), or with changes to the Xen hard limit, but we will
  * recover from these in time.
@@ -482,9 +482,10 @@ static void balloon_process(struct work_struct *work)
        enum bp_state state = BP_DONE;
        long credit;
 
-       mutex_lock(&balloon_mutex);
 
        do {
+               mutex_lock(&balloon_mutex);
+
                credit = current_credit();
 
                if (credit > 0) {
@@ -499,17 +500,15 @@ static void balloon_process(struct work_struct *work)
 
                state = update_schedule(state);
 
-#ifndef CONFIG_PREEMPT
-               if (need_resched())
-                       schedule();
-#endif
+               mutex_unlock(&balloon_mutex);
+
+               cond_resched();
+
        } while (credit && state == BP_DONE);
 
        /* Schedule more work if there is some still to be done. */
        if (state == BP_EAGAIN)
                schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);
-
-       mutex_unlock(&balloon_mutex);
 }
 
 /* Resets the Xen limit, sets new target, and kicks off processing. */
index 67b9163db7185402b0ff3811c5363c1a1022e2c7..0dbb222daaf1c694b1f073f3e206f755f5f77cc6 100644 (file)
@@ -568,12 +568,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
 
        pr_debug("priv %p\n", priv);
 
+       mutex_lock(&priv->lock);
        while (!list_empty(&priv->maps)) {
                map = list_entry(priv->maps.next, struct grant_map, next);
                list_del(&map->next);
                gntdev_put_map(NULL /* already removed */, map);
        }
        WARN_ON(!list_empty(&priv->freeable_maps));
+       mutex_unlock(&priv->lock);
 
        if (use_ptemod)
                mmu_notifier_unregister(&priv->mn, priv->mm);
index 9ad327238ba931243967455b5790916dc6b184f1..e30353575d5da11f75e8c927ba53945a23b73d76 100644 (file)
@@ -814,8 +814,10 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr)
 
        rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles,
                               addrs);
-       if (!rv)
+       if (!rv) {
                vunmap(vaddr);
+               free_xenballooned_pages(node->nr_handles, node->hvm.pages);
+       }
        else
                WARN(1, "Leaking %p, size %u page(s)\n", vaddr,
                     node->nr_handles);
index 510040b04c964dbdeab4ab47c29b789fef5c4b5f..b1dc5188804831af2d58478b700b424e5d78d895 100644 (file)
@@ -540,8 +540,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb,
        unlock_new_inode(inode);
        return inode;
 error:
-       unlock_new_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        return ERR_PTR(retval);
 
 }
index 09e4433717b8795c2c7c8c76452887ec27a91be4..e8aa57dc8d6dff5a7a46899d2ba94a4ec0b715b1 100644 (file)
@@ -149,8 +149,7 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
        unlock_new_inode(inode);
        return inode;
 error:
-       unlock_new_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        return ERR_PTR(retval);
 
 }
index 0ef5cc13fae26f8899cad7ed30b59344c79120d4..81220b2203c61f1033bc5a4a0666f9b7b96f08df 100644 (file)
@@ -44,6 +44,8 @@
 #define BTRFS_INODE_IN_DELALLOC_LIST           9
 #define BTRFS_INODE_READDIO_NEED_LOCK          10
 #define BTRFS_INODE_HAS_PROPS                  11
+/* DIO is ready to submit */
+#define BTRFS_INODE_DIO_READY                  12
 /*
  * The following 3 bits are meant only for the btree inode.
  * When any of them is set, it means an error happened while writing an
index 80a9aefb0c46fc179119d8ad67eb9f8bff687ac1..aac314e14188facff9ed95136eab647709352359 100644 (file)
@@ -1778,6 +1778,7 @@ struct btrfs_fs_info {
        spinlock_t unused_bgs_lock;
        struct list_head unused_bgs;
        struct mutex unused_bg_unpin_mutex;
+       struct mutex delete_unused_bgs_mutex;
 
        /* For btrfs to record security options */
        struct security_mnt_opts security_opts;
index 862fbc206755511a6bd3a02eeaa525e992c545bc..564a7de17d99831083c46bc19fd859d40a5d51a2 100644 (file)
@@ -378,7 +378,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
 
        ret = btrfs_kobj_add_device(tgt_device->fs_devices, tgt_device);
        if (ret)
-               btrfs_error(root->fs_info, ret, "kobj add dev failed");
+               btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret);
 
        printk_in_rcu(KERN_INFO
                      "BTRFS: dev_replace from %s (devid %llu) to %s started\n",
index 3f43bfea3684a13e378fbdd3d364c0635e14daca..f556c3732c2c16e22e0bcbd35f9ee1277179be5b 100644 (file)
@@ -1751,6 +1751,7 @@ static int cleaner_kthread(void *arg)
 {
        struct btrfs_root *root = arg;
        int again;
+       struct btrfs_trans_handle *trans;
 
        do {
                again = 0;
@@ -1772,7 +1773,6 @@ static int cleaner_kthread(void *arg)
                }
 
                btrfs_run_delayed_iputs(root);
-               btrfs_delete_unused_bgs(root->fs_info);
                again = btrfs_clean_one_deleted_snapshot(root);
                mutex_unlock(&root->fs_info->cleaner_mutex);
 
@@ -1781,6 +1781,16 @@ static int cleaner_kthread(void *arg)
                 * needn't do anything special here.
                 */
                btrfs_run_defrag_inodes(root->fs_info);
+
+               /*
+                * Acquires fs_info->delete_unused_bgs_mutex to avoid racing
+                * with relocation (btrfs_relocate_chunk) and relocation
+                * acquires fs_info->cleaner_mutex (btrfs_relocate_block_group)
+                * after acquiring fs_info->delete_unused_bgs_mutex. So we
+                * can't hold, nor need to, fs_info->cleaner_mutex when deleting
+                * unused block groups.
+                */
+               btrfs_delete_unused_bgs(root->fs_info);
 sleep:
                if (!try_to_freeze() && !again) {
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -1789,6 +1799,34 @@ sleep:
                        __set_current_state(TASK_RUNNING);
                }
        } while (!kthread_should_stop());
+
+       /*
+        * Transaction kthread is stopped before us and wakes us up.
+        * However we might have started a new transaction and COWed some
+        * tree blocks when deleting unused block groups for example. So
+        * make sure we commit the transaction we started to have a clean
+        * shutdown when evicting the btree inode - if it has dirty pages
+        * when we do the final iput() on it, eviction will trigger a
+        * writeback for it which will fail with null pointer dereferences
+        * since work queues and other resources were already released and
+        * destroyed by the time the iput/eviction/writeback is made.
+        */
+       trans = btrfs_attach_transaction(root);
+       if (IS_ERR(trans)) {
+               if (PTR_ERR(trans) != -ENOENT)
+                       btrfs_err(root->fs_info,
+                                 "cleaner transaction attach returned %ld",
+                                 PTR_ERR(trans));
+       } else {
+               int ret;
+
+               ret = btrfs_commit_transaction(trans, root);
+               if (ret)
+                       btrfs_err(root->fs_info,
+                                 "cleaner open transaction commit returned %d",
+                                 ret);
+       }
+
        return 0;
 }
 
@@ -2492,6 +2530,7 @@ int open_ctree(struct super_block *sb,
        spin_lock_init(&fs_info->unused_bgs_lock);
        rwlock_init(&fs_info->tree_mod_log_lock);
        mutex_init(&fs_info->unused_bg_unpin_mutex);
+       mutex_init(&fs_info->delete_unused_bgs_mutex);
        mutex_init(&fs_info->reloc_mutex);
        mutex_init(&fs_info->delalloc_root_mutex);
        seqlock_init(&fs_info->profiles_lock);
@@ -2803,6 +2842,7 @@ int open_ctree(struct super_block *sb,
            !extent_buffer_uptodate(chunk_root->node)) {
                printk(KERN_ERR "BTRFS: failed to read chunk root on %s\n",
                       sb->s_id);
+               chunk_root->node = NULL;
                goto fail_tree_roots;
        }
        btrfs_set_root_node(&chunk_root->root_item, chunk_root->node);
@@ -2840,7 +2880,7 @@ retry_root_backup:
            !extent_buffer_uptodate(tree_root->node)) {
                printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n",
                       sb->s_id);
-
+               tree_root->node = NULL;
                goto recovery_tree_root;
        }
 
index 38b76cc02f486db1e9d7f887860aba8137d61205..07204bf601edac25ad2757bbd7c85961eeabc56c 100644 (file)
@@ -2296,9 +2296,22 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
 static inline struct btrfs_delayed_ref_node *
 select_delayed_ref(struct btrfs_delayed_ref_head *head)
 {
+       struct btrfs_delayed_ref_node *ref;
+
        if (list_empty(&head->ref_list))
                return NULL;
 
+       /*
+        * Select a delayed ref of type BTRFS_ADD_DELAYED_REF first.
+        * This is to prevent a ref count from going down to zero, which deletes
+        * the extent item from the extent tree, when there still are references
+        * to add, which would fail because they would not find the extent item.
+        */
+       list_for_each_entry(ref, &head->ref_list, list) {
+               if (ref->action == BTRFS_ADD_DELAYED_REF)
+                       return ref;
+       }
+
        return list_entry(head->ref_list.next, struct btrfs_delayed_ref_node,
                          list);
 }
@@ -4214,6 +4227,24 @@ out:
        space_info->chunk_alloc = 0;
        spin_unlock(&space_info->lock);
        mutex_unlock(&fs_info->chunk_mutex);
+       /*
+        * When we allocate a new chunk we reserve space in the chunk block
+        * reserve to make sure we can COW nodes/leafs in the chunk tree or
+        * add new nodes/leafs to it if we end up needing to do it when
+        * inserting the chunk item and updating device items as part of the
+        * second phase of chunk allocation, performed by
+        * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a
+        * large number of new block groups to create in our transaction
+        * handle's new_bgs list to avoid exhausting the chunk block reserve
+        * in extreme cases - like having a single transaction create many new
+        * block groups when starting to write out the free space caches of all
+        * the block groups that were made dirty during the lifetime of the
+        * transaction.
+        */
+       if (trans->chunk_bytes_reserved >= (2 * 1024 * 1024ull)) {
+               btrfs_create_pending_block_groups(trans, trans->root);
+               btrfs_trans_release_chunk_metadata(trans);
+       }
        return ret;
 }
 
@@ -9889,6 +9920,8 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
                }
                spin_unlock(&fs_info->unused_bgs_lock);
 
+               mutex_lock(&root->fs_info->delete_unused_bgs_mutex);
+
                /* Don't want to race with allocators so take the groups_sem */
                down_write(&space_info->groups_sem);
                spin_lock(&block_group->lock);
@@ -9983,6 +10016,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
 end_trans:
                btrfs_end_transaction(trans, root);
 next:
+               mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                btrfs_put_block_group(block_group);
                spin_lock(&fs_info->unused_bgs_lock);
        }
index f6a596d5a6374f1dbf66279e24ef17aed9ff399d..d4a582ac3f730f82299e997d0866e3caecacac7b 100644 (file)
@@ -246,6 +246,7 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
 {
        struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
        struct rb_root *rbroot = &root->free_ino_pinned->free_space_offset;
+       spinlock_t *rbroot_lock = &root->free_ino_pinned->tree_lock;
        struct btrfs_free_space *info;
        struct rb_node *n;
        u64 count;
@@ -254,24 +255,30 @@ void btrfs_unpin_free_ino(struct btrfs_root *root)
                return;
 
        while (1) {
+               bool add_to_ctl = true;
+
+               spin_lock(rbroot_lock);
                n = rb_first(rbroot);
-               if (!n)
+               if (!n) {
+                       spin_unlock(rbroot_lock);
                        break;
+               }
 
                info = rb_entry(n, struct btrfs_free_space, offset_index);
                BUG_ON(info->bitmap); /* Logic error */
 
                if (info->offset > root->ino_cache_progress)
-                       goto free;
+                       add_to_ctl = false;
                else if (info->offset + info->bytes > root->ino_cache_progress)
                        count = root->ino_cache_progress - info->offset + 1;
                else
                        count = info->bytes;
 
-               __btrfs_add_free_space(ctl, info->offset, count);
-free:
                rb_erase(&info->offset_index, rbroot);
-               kfree(info);
+               spin_unlock(rbroot_lock);
+               if (add_to_ctl)
+                       __btrfs_add_free_space(ctl, info->offset, count);
+               kmem_cache_free(btrfs_free_space_cachep, info);
        }
 }
 
index 855935f6671ae59b1b025c3916d553bc689191ef..e33dff356460687fcade4b56202f83f318e3ebb4 100644 (file)
@@ -4209,7 +4209,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        u64 extent_num_bytes = 0;
        u64 extent_offset = 0;
        u64 item_end = 0;
-       u64 last_size = (u64)-1;
+       u64 last_size = new_size;
        u32 found_type = (u8)-1;
        int found_extent;
        int del_item;
@@ -4493,8 +4493,7 @@ out:
                        btrfs_abort_transaction(trans, root, ret);
        }
 error:
-       if (last_size != (u64)-1 &&
-           root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
+       if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
                btrfs_ordered_update_i_size(inode, last_size, NULL);
 
        btrfs_free_path(path);
@@ -4989,8 +4988,9 @@ static void evict_inode_truncate_pages(struct inode *inode)
        /*
         * Keep looping until we have no more ranges in the io tree.
         * We can have ongoing bios started by readpages (called from readahead)
-        * that didn't get their end io callbacks called yet or they are still
-        * in progress ((extent_io.c:end_bio_extent_readpage()). This means some
+        * that have their endio callback (extent_io.c:end_bio_extent_readpage)
+        * still in progress (unlocked the pages in the bio but did not yet
+        * unlocked the ranges in the io tree). Therefore this means some
         * ranges can still be locked and eviction started because before
         * submitting those bios, which are executed by a separate task (work
         * queue kthread), inode references (inode->i_count) were not taken
@@ -7546,6 +7546,7 @@ unlock:
 
                current->journal_info = outstanding_extents;
                btrfs_free_reserved_data_space(inode, len);
+               set_bit(BTRFS_INODE_DIO_READY, &BTRFS_I(inode)->runtime_flags);
        }
 
        /*
@@ -7871,8 +7872,6 @@ static void btrfs_endio_direct_write(struct bio *bio, int err)
        struct bio *dio_bio;
        int ret;
 
-       if (err)
-               goto out_done;
 again:
        ret = btrfs_dec_test_first_ordered_pending(inode, &ordered,
                                                   &ordered_offset,
@@ -7895,7 +7894,6 @@ out_test:
                ordered = NULL;
                goto again;
        }
-out_done:
        dio_bio = dip->dio_bio;
 
        kfree(dip);
@@ -8163,9 +8161,8 @@ out_err:
 static void btrfs_submit_direct(int rw, struct bio *dio_bio,
                                struct inode *inode, loff_t file_offset)
 {
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_dio_private *dip;
-       struct bio *io_bio;
+       struct btrfs_dio_private *dip = NULL;
+       struct bio *io_bio = NULL;
        struct btrfs_io_bio *btrfs_bio;
        int skip_sum;
        int write = rw & REQ_WRITE;
@@ -8182,7 +8179,7 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
        dip = kzalloc(sizeof(*dip), GFP_NOFS);
        if (!dip) {
                ret = -ENOMEM;
-               goto free_io_bio;
+               goto free_ordered;
        }
 
        dip->private = dio_bio->bi_private;
@@ -8210,25 +8207,55 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
 
        if (btrfs_bio->end_io)
                btrfs_bio->end_io(btrfs_bio, ret);
-free_io_bio:
-       bio_put(io_bio);
 
 free_ordered:
        /*
-        * If this is a write, we need to clean up the reserved space and kill
-        * the ordered extent.
+        * If we arrived here it means either we failed to submit the dip
+        * or we either failed to clone the dio_bio or failed to allocate the
+        * dip. If we cloned the dio_bio and allocated the dip, we can just
+        * call bio_endio against our io_bio so that we get proper resource
+        * cleanup if we fail to submit the dip, otherwise, we must do the
+        * same as btrfs_endio_direct_[write|read] because we can't call these
+        * callbacks - they require an allocated dip and a clone of dio_bio.
         */
-       if (write) {
-               struct btrfs_ordered_extent *ordered;
-               ordered = btrfs_lookup_ordered_extent(inode, file_offset);
-               if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
-                   !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
-                       btrfs_free_reserved_extent(root, ordered->start,
-                                                  ordered->disk_len, 1);
-               btrfs_put_ordered_extent(ordered);
-               btrfs_put_ordered_extent(ordered);
+       if (io_bio && dip) {
+               bio_endio(io_bio, ret);
+               /*
+                * The end io callbacks free our dip, do the final put on io_bio
+                * and all the cleanup and final put for dio_bio (through
+                * dio_end_io()).
+                */
+               dip = NULL;
+               io_bio = NULL;
+       } else {
+               if (write) {
+                       struct btrfs_ordered_extent *ordered;
+
+                       ordered = btrfs_lookup_ordered_extent(inode,
+                                                             file_offset);
+                       set_bit(BTRFS_ORDERED_IOERR, &ordered->flags);
+                       /*
+                        * Decrements our ref on the ordered extent and removes
+                        * the ordered extent from the inode's ordered tree,
+                        * doing all the proper resource cleanup such as for the
+                        * reserved space and waking up any waiters for this
+                        * ordered extent (through btrfs_remove_ordered_extent).
+                        */
+                       btrfs_finish_ordered_io(ordered);
+               } else {
+                       unlock_extent(&BTRFS_I(inode)->io_tree, file_offset,
+                             file_offset + dio_bio->bi_iter.bi_size - 1);
+               }
+               clear_bit(BIO_UPTODATE, &dio_bio->bi_flags);
+               /*
+                * Releases and cleans up our dio_bio, no need to bio_put()
+                * nor bio_endio()/bio_io_error() against dio_bio.
+                */
+               dio_end_io(dio_bio, ret);
        }
-       bio_endio(dio_bio, ret);
+       if (io_bio)
+               bio_put(io_bio);
+       kfree(dip);
 }
 
 static ssize_t check_direct_IO(struct btrfs_root *root, struct kiocb *iocb,
@@ -8330,9 +8357,18 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                                   btrfs_submit_direct, flags);
        if (iov_iter_rw(iter) == WRITE) {
                current->journal_info = NULL;
-               if (ret < 0 && ret != -EIOCBQUEUED)
-                       btrfs_delalloc_release_space(inode, count);
-               else if (ret >= 0 && (size_t)ret < count)
+               if (ret < 0 && ret != -EIOCBQUEUED) {
+                       /*
+                        * If the error comes from submitting stage,
+                        * btrfs_get_blocsk_direct() has free'd data space,
+                        * and metadata space will be handled by
+                        * finish_ordered_fn, don't do that again to make
+                        * sure bytes_may_use is correct.
+                        */
+                       if (!test_and_clear_bit(BTRFS_INODE_DIO_READY,
+                                    &BTRFS_I(inode)->runtime_flags))
+                               btrfs_delalloc_release_space(inode, count);
+               } else if (ret >= 0 && (size_t)ret < count)
                        btrfs_delalloc_release_space(inode,
                                                     count - (size_t)ret);
        }
index c86b835da7a8739ec16396d589ccb651278ab44d..0770c91586ca694e1f9c142fb653cf02c02dd686 100644 (file)
@@ -87,7 +87,8 @@ struct btrfs_ioctl_received_subvol_args_32 {
 
 
 static int btrfs_clone(struct inode *src, struct inode *inode,
-                      u64 off, u64 olen, u64 olen_aligned, u64 destoff);
+                      u64 off, u64 olen, u64 olen_aligned, u64 destoff,
+                      int no_time_update);
 
 /* Mask out flags that are inappropriate for the given type of inode. */
 static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@ -2765,14 +2766,11 @@ out:
        return ret;
 }
 
-static struct page *extent_same_get_page(struct inode *inode, u64 off)
+static struct page *extent_same_get_page(struct inode *inode, pgoff_t index)
 {
        struct page *page;
-       pgoff_t index;
        struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
 
-       index = off >> PAGE_CACHE_SHIFT;
-
        page = grab_cache_page(inode->i_mapping, index);
        if (!page)
                return NULL;
@@ -2793,6 +2791,20 @@ static struct page *extent_same_get_page(struct inode *inode, u64 off)
        return page;
 }
 
+static int gather_extent_pages(struct inode *inode, struct page **pages,
+                              int num_pages, u64 off)
+{
+       int i;
+       pgoff_t index = off >> PAGE_CACHE_SHIFT;
+
+       for (i = 0; i < num_pages; i++) {
+               pages[i] = extent_same_get_page(inode, index + i);
+               if (!pages[i])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
 static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
 {
        /* do any pending delalloc/csum calc on src, one way or
@@ -2818,52 +2830,120 @@ static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
        }
 }
 
-static void btrfs_double_unlock(struct inode *inode1, u64 loff1,
-                               struct inode *inode2, u64 loff2, u64 len)
+static void btrfs_double_inode_unlock(struct inode *inode1, struct inode *inode2)
 {
-       unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1);
-       unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1);
-
        mutex_unlock(&inode1->i_mutex);
        mutex_unlock(&inode2->i_mutex);
 }
 
-static void btrfs_double_lock(struct inode *inode1, u64 loff1,
-                             struct inode *inode2, u64 loff2, u64 len)
+static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2)
+{
+       if (inode1 < inode2)
+               swap(inode1, inode2);
+
+       mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
+       if (inode1 != inode2)
+               mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
+}
+
+static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1,
+                                     struct inode *inode2, u64 loff2, u64 len)
+{
+       unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1);
+       unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1);
+}
+
+static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
+                                    struct inode *inode2, u64 loff2, u64 len)
 {
        if (inode1 < inode2) {
                swap(inode1, inode2);
                swap(loff1, loff2);
        }
-
-       mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
        lock_extent_range(inode1, loff1, len);
-       if (inode1 != inode2) {
-               mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
+       if (inode1 != inode2)
                lock_extent_range(inode2, loff2, len);
+}
+
+struct cmp_pages {
+       int             num_pages;
+       struct page     **src_pages;
+       struct page     **dst_pages;
+};
+
+static void btrfs_cmp_data_free(struct cmp_pages *cmp)
+{
+       int i;
+       struct page *pg;
+
+       for (i = 0; i < cmp->num_pages; i++) {
+               pg = cmp->src_pages[i];
+               if (pg)
+                       page_cache_release(pg);
+               pg = cmp->dst_pages[i];
+               if (pg)
+                       page_cache_release(pg);
+       }
+       kfree(cmp->src_pages);
+       kfree(cmp->dst_pages);
+}
+
+static int btrfs_cmp_data_prepare(struct inode *src, u64 loff,
+                                 struct inode *dst, u64 dst_loff,
+                                 u64 len, struct cmp_pages *cmp)
+{
+       int ret;
+       int num_pages = PAGE_CACHE_ALIGN(len) >> PAGE_CACHE_SHIFT;
+       struct page **src_pgarr, **dst_pgarr;
+
+       /*
+        * We must gather up all the pages before we initiate our
+        * extent locking. We use an array for the page pointers. Size
+        * of the array is bounded by len, which is in turn bounded by
+        * BTRFS_MAX_DEDUPE_LEN.
+        */
+       src_pgarr = kzalloc(num_pages * sizeof(struct page *), GFP_NOFS);
+       dst_pgarr = kzalloc(num_pages * sizeof(struct page *), GFP_NOFS);
+       if (!src_pgarr || !dst_pgarr) {
+               kfree(src_pgarr);
+               kfree(dst_pgarr);
+               return -ENOMEM;
        }
+       cmp->num_pages = num_pages;
+       cmp->src_pages = src_pgarr;
+       cmp->dst_pages = dst_pgarr;
+
+       ret = gather_extent_pages(src, cmp->src_pages, cmp->num_pages, loff);
+       if (ret)
+               goto out;
+
+       ret = gather_extent_pages(dst, cmp->dst_pages, cmp->num_pages, dst_loff);
+
+out:
+       if (ret)
+               btrfs_cmp_data_free(cmp);
+       return 0;
 }
 
 static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
-                         u64 dst_loff, u64 len)
+                         u64 dst_loff, u64 len, struct cmp_pages *cmp)
 {
        int ret = 0;
+       int i;
        struct page *src_page, *dst_page;
        unsigned int cmp_len = PAGE_CACHE_SIZE;
        void *addr, *dst_addr;
 
+       i = 0;
        while (len) {
                if (len < PAGE_CACHE_SIZE)
                        cmp_len = len;
 
-               src_page = extent_same_get_page(src, loff);
-               if (!src_page)
-                       return -EINVAL;
-               dst_page = extent_same_get_page(dst, dst_loff);
-               if (!dst_page) {
-                       page_cache_release(src_page);
-                       return -EINVAL;
-               }
+               BUG_ON(i >= cmp->num_pages);
+
+               src_page = cmp->src_pages[i];
+               dst_page = cmp->dst_pages[i];
+
                addr = kmap_atomic(src_page);
                dst_addr = kmap_atomic(dst_page);
 
@@ -2875,15 +2955,12 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
 
                kunmap_atomic(addr);
                kunmap_atomic(dst_addr);
-               page_cache_release(src_page);
-               page_cache_release(dst_page);
 
                if (ret)
                        break;
 
-               loff += cmp_len;
-               dst_loff += cmp_len;
                len -= cmp_len;
+               i++;
        }
 
        return ret;
@@ -2914,27 +2991,62 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
 {
        int ret;
        u64 len = olen;
+       struct cmp_pages cmp;
+       int same_inode = 0;
+       u64 same_lock_start = 0;
+       u64 same_lock_len = 0;
 
-       /*
-        * btrfs_clone() can't handle extents in the same file
-        * yet. Once that works, we can drop this check and replace it
-        * with a check for the same inode, but overlapping extents.
-        */
        if (src == dst)
-               return -EINVAL;
+               same_inode = 1;
 
        if (len == 0)
                return 0;
 
-       btrfs_double_lock(src, loff, dst, dst_loff, len);
+       if (same_inode) {
+               mutex_lock(&src->i_mutex);
 
-       ret = extent_same_check_offsets(src, loff, &len, olen);
-       if (ret)
-               goto out_unlock;
+               ret = extent_same_check_offsets(src, loff, &len, olen);
+               if (ret)
+                       goto out_unlock;
 
-       ret = extent_same_check_offsets(dst, dst_loff, &len, olen);
-       if (ret)
-               goto out_unlock;
+               /*
+                * Single inode case wants the same checks, except we
+                * don't want our length pushed out past i_size as
+                * comparing that data range makes no sense.
+                *
+                * extent_same_check_offsets() will do this for an
+                * unaligned length at i_size, so catch it here and
+                * reject the request.
+                *
+                * This effectively means we require aligned extents
+                * for the single-inode case, whereas the other cases
+                * allow an unaligned length so long as it ends at
+                * i_size.
+                */
+               if (len != olen) {
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+
+               /* Check for overlapping ranges */
+               if (dst_loff + len > loff && dst_loff < loff + len) {
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+
+               same_lock_start = min_t(u64, loff, dst_loff);
+               same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start;
+       } else {
+               btrfs_double_inode_lock(src, dst);
+
+               ret = extent_same_check_offsets(src, loff, &len, olen);
+               if (ret)
+                       goto out_unlock;
+
+               ret = extent_same_check_offsets(dst, dst_loff, &len, olen);
+               if (ret)
+                       goto out_unlock;
+       }
 
        /* don't make the dst file partly checksummed */
        if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
@@ -2943,12 +3055,32 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
                goto out_unlock;
        }
 
-       ret = btrfs_cmp_data(src, loff, dst, dst_loff, len);
+       ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, &cmp);
+       if (ret)
+               goto out_unlock;
+
+       if (same_inode)
+               lock_extent_range(src, same_lock_start, same_lock_len);
+       else
+               btrfs_double_extent_lock(src, loff, dst, dst_loff, len);
+
+       /* pass original length for comparison so we stay within i_size */
+       ret = btrfs_cmp_data(src, loff, dst, dst_loff, olen, &cmp);
        if (ret == 0)
-               ret = btrfs_clone(src, dst, loff, olen, len, dst_loff);
+               ret = btrfs_clone(src, dst, loff, olen, len, dst_loff, 1);
+
+       if (same_inode)
+               unlock_extent(&BTRFS_I(src)->io_tree, same_lock_start,
+                             same_lock_start + same_lock_len - 1);
+       else
+               btrfs_double_extent_unlock(src, loff, dst, dst_loff, len);
 
+       btrfs_cmp_data_free(&cmp);
 out_unlock:
-       btrfs_double_unlock(src, loff, dst, dst_loff, len);
+       if (same_inode)
+               mutex_unlock(&src->i_mutex);
+       else
+               btrfs_double_inode_unlock(src, dst);
 
        return ret;
 }
@@ -2958,7 +3090,7 @@ out_unlock:
 static long btrfs_ioctl_file_extent_same(struct file *file,
                        struct btrfs_ioctl_same_args __user *argp)
 {
-       struct btrfs_ioctl_same_args *same;
+       struct btrfs_ioctl_same_args *same = NULL;
        struct btrfs_ioctl_same_extent_info *info;
        struct inode *src = file_inode(file);
        u64 off;
@@ -2988,6 +3120,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
 
        if (IS_ERR(same)) {
                ret = PTR_ERR(same);
+               same = NULL;
                goto out;
        }
 
@@ -3058,6 +3191,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
 
 out:
        mnt_drop_write_file(file);
+       kfree(same);
        return ret;
 }
 
@@ -3100,13 +3234,15 @@ static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
                                     struct inode *inode,
                                     u64 endoff,
                                     const u64 destoff,
-                                    const u64 olen)
+                                    const u64 olen,
+                                    int no_time_update)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
 
        inode_inc_iversion(inode);
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       if (!no_time_update)
+               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        /*
         * We round up to the block size at eof when determining which
         * extents to clone above, but shouldn't round up the file size.
@@ -3191,13 +3327,13 @@ static void clone_update_extent_map(struct inode *inode,
  * @inode: Inode to clone to
  * @off: Offset within source to start clone from
  * @olen: Original length, passed by user, of range to clone
- * @olen_aligned: Block-aligned value of olen, extent_same uses
- *               identical values here
+ * @olen_aligned: Block-aligned value of olen
  * @destoff: Offset within @inode to start clone
+ * @no_time_update: Whether to update mtime/ctime on the target inode
  */
 static int btrfs_clone(struct inode *src, struct inode *inode,
                       const u64 off, const u64 olen, const u64 olen_aligned,
-                      const u64 destoff)
+                      const u64 destoff, int no_time_update)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_path *path = NULL;
@@ -3452,6 +3588,20 @@ process_slot:
                                u64 trim = 0;
                                u64 aligned_end = 0;
 
+                               /*
+                                * Don't copy an inline extent into an offset
+                                * greater than zero. Having an inline extent
+                                * at such an offset results in chaos as btrfs
+                                * isn't prepared for such cases. Just skip
+                                * this case for the same reasons as commented
+                                * at btrfs_ioctl_clone().
+                                */
+                               if (last_dest_end > 0) {
+                                       ret = -EOPNOTSUPP;
+                                       btrfs_end_transaction(trans, root);
+                                       goto out;
+                               }
+
                                if (off > key.offset) {
                                        skip = off - key.offset;
                                        new_key.offset += skip;
@@ -3521,7 +3671,8 @@ process_slot:
                                              root->sectorsize);
                        ret = clone_finish_inode_update(trans, inode,
                                                        last_dest_end,
-                                                       destoff, olen);
+                                                       destoff, olen,
+                                                       no_time_update);
                        if (ret)
                                goto out;
                        if (new_key.offset + datal >= destoff + len)
@@ -3559,7 +3710,7 @@ process_slot:
                clone_update_extent_map(inode, trans, NULL, last_dest_end,
                                        destoff + len - last_dest_end);
                ret = clone_finish_inode_update(trans, inode, destoff + len,
-                                               destoff, olen);
+                                               destoff, olen, no_time_update);
        }
 
 out:
@@ -3696,7 +3847,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                lock_extent_range(inode, destoff, len);
        }
 
-       ret = btrfs_clone(src, inode, off, olen, len, destoff);
+       ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
 
        if (same_inode) {
                u64 lock_start = min_t(u64, off, destoff);
index 89656d799ff6fa3772b52cb17d535ebdc1cbb910..52170cf1757e3d25192a6cf6211a9d2edaa52751 100644 (file)
@@ -552,6 +552,10 @@ void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
        trace_btrfs_ordered_extent_put(entry->inode, entry);
 
        if (atomic_dec_and_test(&entry->refs)) {
+               ASSERT(list_empty(&entry->log_list));
+               ASSERT(list_empty(&entry->trans_list));
+               ASSERT(list_empty(&entry->root_extent_list));
+               ASSERT(RB_EMPTY_NODE(&entry->rb_node));
                if (entry->inode)
                        btrfs_add_delayed_iput(entry->inode);
                while (!list_empty(&entry->list)) {
@@ -579,6 +583,7 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        spin_lock_irq(&tree->lock);
        node = &entry->rb_node;
        rb_erase(node, &tree->tree);
+       RB_CLEAR_NODE(node);
        if (tree->last == node)
                tree->last = NULL;
        set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
index d5f1f033b7a00f3c2e2826e336ae5ca5b3e31d4a..8a820295657686d634e3a5ded2ee21b5dcefc026 100644 (file)
@@ -1349,6 +1349,11 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
        struct btrfs_root *quota_root;
        struct btrfs_qgroup *qgroup;
        int ret = 0;
+       /* Sometimes we would want to clear the limit on this qgroup.
+        * To meet this requirement, we treat the -1 as a special value
+        * which tell kernel to clear the limit on this qgroup.
+        */
+       const u64 CLEAR_VALUE = -1;
 
        mutex_lock(&fs_info->qgroup_ioctl_lock);
        quota_root = fs_info->quota_root;
@@ -1364,14 +1369,42 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
        }
 
        spin_lock(&fs_info->qgroup_lock);
-       if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
-               qgroup->max_rfer = limit->max_rfer;
-       if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
-               qgroup->max_excl = limit->max_excl;
-       if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_RFER)
-               qgroup->rsv_rfer = limit->rsv_rfer;
-       if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_EXCL)
-               qgroup->rsv_excl = limit->rsv_excl;
+       if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER) {
+               if (limit->max_rfer == CLEAR_VALUE) {
+                       qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER;
+                       limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER;
+                       qgroup->max_rfer = 0;
+               } else {
+                       qgroup->max_rfer = limit->max_rfer;
+               }
+       }
+       if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) {
+               if (limit->max_excl == CLEAR_VALUE) {
+                       qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL;
+                       limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL;
+                       qgroup->max_excl = 0;
+               } else {
+                       qgroup->max_excl = limit->max_excl;
+               }
+       }
+       if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_RFER) {
+               if (limit->rsv_rfer == CLEAR_VALUE) {
+                       qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER;
+                       limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER;
+                       qgroup->rsv_rfer = 0;
+               } else {
+                       qgroup->rsv_rfer = limit->rsv_rfer;
+               }
+       }
+       if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_EXCL) {
+               if (limit->rsv_excl == CLEAR_VALUE) {
+                       qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL;
+                       limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL;
+                       qgroup->rsv_excl = 0;
+               } else {
+                       qgroup->rsv_excl = limit->rsv_excl;
+               }
+       }
        qgroup->lim_flags |= limit->flags;
 
        spin_unlock(&fs_info->qgroup_lock);
@@ -1618,6 +1651,11 @@ static int qgroup_update_counters(struct btrfs_fs_info *fs_info,
                                /* Exclusive -> exclusive, nothing changed */
                        }
                }
+
+               /* For exclusive extent, free its reserved bytes too */
+               if (nr_old_roots == 0 && nr_new_roots == 1 &&
+                   cur_new_count == nr_new_roots)
+                       qg->reserved -= num_bytes;
                if (dirty)
                        qgroup_dirty(fs_info, qg);
        }
index 827951fbf7fcb7dac026e48ded6e29f2f723adef..88cbb5995667951192b94c2627f759a771eda9e3 100644 (file)
@@ -4049,7 +4049,7 @@ restart:
        if (trans && progress && err == -ENOSPC) {
                ret = btrfs_force_chunk_alloc(trans, rc->extent_root,
                                              rc->block_group->flags);
-               if (ret == 0) {
+               if (ret == 1) {
                        err = 0;
                        progress = 0;
                        goto restart;
index 9f2feabe99f211f9c8eb5d489c44c85f54754c27..94db0fa5225a9fd493163fc117cd25d8b01b7343 100644 (file)
@@ -3571,7 +3571,6 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
 static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
                                                int is_dev_replace)
 {
-       int ret = 0;
        unsigned int flags = WQ_FREEZABLE | WQ_UNBOUND;
        int max_active = fs_info->thread_pool_size;
 
@@ -3584,34 +3583,36 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
                        fs_info->scrub_workers =
                                btrfs_alloc_workqueue("btrfs-scrub", flags,
                                                      max_active, 4);
-               if (!fs_info->scrub_workers) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!fs_info->scrub_workers)
+                       goto fail_scrub_workers;
+
                fs_info->scrub_wr_completion_workers =
                        btrfs_alloc_workqueue("btrfs-scrubwrc", flags,
                                              max_active, 2);
-               if (!fs_info->scrub_wr_completion_workers) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!fs_info->scrub_wr_completion_workers)
+                       goto fail_scrub_wr_completion_workers;
+
                fs_info->scrub_nocow_workers =
                        btrfs_alloc_workqueue("btrfs-scrubnc", flags, 1, 0);
-               if (!fs_info->scrub_nocow_workers) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!fs_info->scrub_nocow_workers)
+                       goto fail_scrub_nocow_workers;
                fs_info->scrub_parity_workers =
                        btrfs_alloc_workqueue("btrfs-scrubparity", flags,
                                              max_active, 2);
-               if (!fs_info->scrub_parity_workers) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
+               if (!fs_info->scrub_parity_workers)
+                       goto fail_scrub_parity_workers;
        }
        ++fs_info->scrub_workers_refcnt;
-out:
-       return ret;
+       return 0;
+
+fail_scrub_parity_workers:
+       btrfs_destroy_workqueue(fs_info->scrub_nocow_workers);
+fail_scrub_nocow_workers:
+       btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers);
+fail_scrub_wr_completion_workers:
+       btrfs_destroy_workqueue(fs_info->scrub_workers);
+fail_scrub_workers:
+       return -ENOMEM;
 }
 
 static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
index c0f18e7266b673c22357ebb033e40a4ec6e28b60..f5021fcb154e3bfa3773a79d94ee4750be48ca0d 100644 (file)
@@ -761,7 +761,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 
        if (!list_empty(&trans->ordered)) {
                spin_lock(&info->trans_lock);
-               list_splice(&trans->ordered, &cur_trans->pending_ordered);
+               list_splice_init(&trans->ordered, &cur_trans->pending_ordered);
                spin_unlock(&info->trans_lock);
        }
 
@@ -1866,7 +1866,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        }
 
        spin_lock(&root->fs_info->trans_lock);
-       list_splice(&trans->ordered, &cur_trans->pending_ordered);
+       list_splice_init(&trans->ordered, &cur_trans->pending_ordered);
        if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
                spin_unlock(&root->fs_info->trans_lock);
                atomic_inc(&cur_trans->use_count);
@@ -2152,7 +2152,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 
-       if (current != root->fs_info->transaction_kthread)
+       if (current != root->fs_info->transaction_kthread &&
+           current != root->fs_info->cleaner_kthread)
                btrfs_run_delayed_iputs(root);
 
        return ret;
index 1ce80c1c4eb6c1a414cfe88009c5c1c0e5c14132..9c45431e69aba3a7a8e2d0bcfb8c3b4a18182df2 100644 (file)
@@ -4117,6 +4117,187 @@ static int logged_inode_size(struct btrfs_root *log, struct inode *inode,
        return 0;
 }
 
+/*
+ * At the moment we always log all xattrs. This is to figure out at log replay
+ * time which xattrs must have their deletion replayed. If a xattr is missing
+ * in the log tree and exists in the fs/subvol tree, we delete it. This is
+ * because if a xattr is deleted, the inode is fsynced and a power failure
+ * happens, causing the log to be replayed the next time the fs is mounted,
+ * we want the xattr to not exist anymore (same behaviour as other filesystems
+ * with a journal, ext3/4, xfs, f2fs, etc).
+ */
+static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct inode *inode,
+                               struct btrfs_path *path,
+                               struct btrfs_path *dst_path)
+{
+       int ret;
+       struct btrfs_key key;
+       const u64 ino = btrfs_ino(inode);
+       int ins_nr = 0;
+       int start_slot = 0;
+
+       key.objectid = ino;
+       key.type = BTRFS_XATTR_ITEM_KEY;
+       key.offset = 0;
+
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       while (true) {
+               int slot = path->slots[0];
+               struct extent_buffer *leaf = path->nodes[0];
+               int nritems = btrfs_header_nritems(leaf);
+
+               if (slot >= nritems) {
+                       if (ins_nr > 0) {
+                               u64 last_extent = 0;
+
+                               ret = copy_items(trans, inode, dst_path, path,
+                                                &last_extent, start_slot,
+                                                ins_nr, 1, 0);
+                               /* can't be 1, extent items aren't processed */
+                               ASSERT(ret <= 0);
+                               if (ret < 0)
+                                       return ret;
+                               ins_nr = 0;
+                       }
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               return ret;
+                       else if (ret > 0)
+                               break;
+                       continue;
+               }
+
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+               if (key.objectid != ino || key.type != BTRFS_XATTR_ITEM_KEY)
+                       break;
+
+               if (ins_nr == 0)
+                       start_slot = slot;
+               ins_nr++;
+               path->slots[0]++;
+               cond_resched();
+       }
+       if (ins_nr > 0) {
+               u64 last_extent = 0;
+
+               ret = copy_items(trans, inode, dst_path, path,
+                                &last_extent, start_slot,
+                                ins_nr, 1, 0);
+               /* can't be 1, extent items aren't processed */
+               ASSERT(ret <= 0);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * If the no holes feature is enabled we need to make sure any hole between the
+ * last extent and the i_size of our inode is explicitly marked in the log. This
+ * is to make sure that doing something like:
+ *
+ *      1) create file with 128Kb of data
+ *      2) truncate file to 64Kb
+ *      3) truncate file to 256Kb
+ *      4) fsync file
+ *      5) <crash/power failure>
+ *      6) mount fs and trigger log replay
+ *
+ * Will give us a file with a size of 256Kb, the first 64Kb of data match what
+ * the file had in its first 64Kb of data at step 1 and the last 192Kb of the
+ * file correspond to a hole. The presence of explicit holes in a log tree is
+ * what guarantees that log replay will remove/adjust file extent items in the
+ * fs/subvol tree.
+ *
+ * Here we do not need to care about holes between extents, that is already done
+ * by copy_items(). We also only need to do this in the full sync path, where we
+ * lookup for extents from the fs/subvol tree only. In the fast path case, we
+ * lookup the list of modified extent maps and if any represents a hole, we
+ * insert a corresponding extent representing a hole in the log tree.
+ */
+static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans,
+                                  struct btrfs_root *root,
+                                  struct inode *inode,
+                                  struct btrfs_path *path)
+{
+       int ret;
+       struct btrfs_key key;
+       u64 hole_start;
+       u64 hole_size;
+       struct extent_buffer *leaf;
+       struct btrfs_root *log = root->log_root;
+       const u64 ino = btrfs_ino(inode);
+       const u64 i_size = i_size_read(inode);
+
+       if (!btrfs_fs_incompat(root->fs_info, NO_HOLES))
+               return 0;
+
+       key.objectid = ino;
+       key.type = BTRFS_EXTENT_DATA_KEY;
+       key.offset = (u64)-1;
+
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       ASSERT(ret != 0);
+       if (ret < 0)
+               return ret;
+
+       ASSERT(path->slots[0] > 0);
+       path->slots[0]--;
+       leaf = path->nodes[0];
+       btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+
+       if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY) {
+               /* inode does not have any extents */
+               hole_start = 0;
+               hole_size = i_size;
+       } else {
+               struct btrfs_file_extent_item *extent;
+               u64 len;
+
+               /*
+                * If there's an extent beyond i_size, an explicit hole was
+                * already inserted by copy_items().
+                */
+               if (key.offset >= i_size)
+                       return 0;
+
+               extent = btrfs_item_ptr(leaf, path->slots[0],
+                                       struct btrfs_file_extent_item);
+
+               if (btrfs_file_extent_type(leaf, extent) ==
+                   BTRFS_FILE_EXTENT_INLINE) {
+                       len = btrfs_file_extent_inline_len(leaf,
+                                                          path->slots[0],
+                                                          extent);
+                       ASSERT(len == i_size);
+                       return 0;
+               }
+
+               len = btrfs_file_extent_num_bytes(leaf, extent);
+               /* Last extent goes beyond i_size, no need to log a hole. */
+               if (key.offset + len > i_size)
+                       return 0;
+               hole_start = key.offset + len;
+               hole_size = i_size - hole_start;
+       }
+       btrfs_release_path(path);
+
+       /* Last extent ends at i_size. */
+       if (hole_size == 0)
+               return 0;
+
+       hole_size = ALIGN(hole_size, root->sectorsize);
+       ret = btrfs_insert_file_extent(trans, log, ino, hole_start, 0, 0,
+                                      hole_size, 0, hole_size, 0, 0, 0);
+       return ret;
+}
+
 /* log a single inode in the tree log.
  * At least one parent directory for this inode must exist in the tree
  * or be logged already.
@@ -4155,6 +4336,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        u64 ino = btrfs_ino(inode);
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        u64 logged_isize = 0;
+       bool need_log_inode_item = true;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -4263,11 +4445,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                } else {
                        if (inode_only == LOG_INODE_ALL)
                                fast_search = true;
-                       ret = log_inode_item(trans, log, dst_path, inode);
-                       if (ret) {
-                               err = ret;
-                               goto out_unlock;
-                       }
                        goto log_extents;
                }
 
@@ -4290,6 +4467,28 @@ again:
                if (min_key.type > max_key.type)
                        break;
 
+               if (min_key.type == BTRFS_INODE_ITEM_KEY)
+                       need_log_inode_item = false;
+
+               /* Skip xattrs, we log them later with btrfs_log_all_xattrs() */
+               if (min_key.type == BTRFS_XATTR_ITEM_KEY) {
+                       if (ins_nr == 0)
+                               goto next_slot;
+                       ret = copy_items(trans, inode, dst_path, path,
+                                        &last_extent, ins_start_slot,
+                                        ins_nr, inode_only, logged_isize);
+                       if (ret < 0) {
+                               err = ret;
+                               goto out_unlock;
+                       }
+                       ins_nr = 0;
+                       if (ret) {
+                               btrfs_release_path(path);
+                               continue;
+                       }
+                       goto next_slot;
+               }
+
                src = path->nodes[0];
                if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) {
                        ins_nr++;
@@ -4357,9 +4556,26 @@ next_slot:
                ins_nr = 0;
        }
 
+       btrfs_release_path(path);
+       btrfs_release_path(dst_path);
+       err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path);
+       if (err)
+               goto out_unlock;
+       if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) {
+               btrfs_release_path(path);
+               btrfs_release_path(dst_path);
+               err = btrfs_log_trailing_hole(trans, root, inode, path);
+               if (err)
+                       goto out_unlock;
+       }
 log_extents:
        btrfs_release_path(path);
        btrfs_release_path(dst_path);
+       if (need_log_inode_item) {
+               err = log_inode_item(trans, log, dst_path, inode);
+               if (err)
+                       goto out_unlock;
+       }
        if (fast_search) {
                /*
                 * Some ordered extents started by fsync might have completed
index 4b438b4c8c9195b3aaf11519339719efbef7b21b..fbe7c104531c9e5eaf8b347f46d0b8a783f88322 100644 (file)
@@ -2766,6 +2766,20 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
        root = root->fs_info->chunk_root;
        extent_root = root->fs_info->extent_root;
 
+       /*
+        * Prevent races with automatic removal of unused block groups.
+        * After we relocate and before we remove the chunk with offset
+        * chunk_offset, automatic removal of the block group can kick in,
+        * resulting in a failure when calling btrfs_remove_chunk() below.
+        *
+        * Make sure to acquire this mutex before doing a tree search (dev
+        * or chunk trees) to find chunks. Otherwise the cleaner kthread might
+        * call btrfs_remove_chunk() (through btrfs_delete_unused_bgs()) after
+        * we release the path used to search the chunk/dev tree and before
+        * the current task acquires this mutex and calls us.
+        */
+       ASSERT(mutex_is_locked(&root->fs_info->delete_unused_bgs_mutex));
+
        ret = btrfs_can_relocate(extent_root, chunk_offset);
        if (ret)
                return -ENOSPC;
@@ -2814,13 +2828,18 @@ again:
        key.type = BTRFS_CHUNK_ITEM_KEY;
 
        while (1) {
+               mutex_lock(&root->fs_info->delete_unused_bgs_mutex);
                ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
-               if (ret < 0)
+               if (ret < 0) {
+                       mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                        goto error;
+               }
                BUG_ON(ret == 0); /* Corruption */
 
                ret = btrfs_previous_item(chunk_root, path, key.objectid,
                                          key.type);
+               if (ret)
+                       mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                if (ret < 0)
                        goto error;
                if (ret > 0)
@@ -2843,6 +2862,7 @@ again:
                        else
                                BUG_ON(ret);
                }
+               mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
 
                if (found_key.offset == 0)
                        break;
@@ -3299,9 +3319,12 @@ again:
                        goto error;
                }
 
+               mutex_lock(&fs_info->delete_unused_bgs_mutex);
                ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0);
-               if (ret < 0)
+               if (ret < 0) {
+                       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        goto error;
+               }
 
                /*
                 * this shouldn't happen, it means the last relocate
@@ -3313,6 +3336,7 @@ again:
                ret = btrfs_previous_item(chunk_root, path, 0,
                                          BTRFS_CHUNK_ITEM_KEY);
                if (ret) {
+                       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        ret = 0;
                        break;
                }
@@ -3321,8 +3345,10 @@ again:
                slot = path->slots[0];
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
 
-               if (found_key.objectid != key.objectid)
+               if (found_key.objectid != key.objectid) {
+                       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        break;
+               }
 
                chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
 
@@ -3335,10 +3361,13 @@ again:
                ret = should_balance_chunk(chunk_root, leaf, chunk,
                                           found_key.offset);
                btrfs_release_path(path);
-               if (!ret)
+               if (!ret) {
+                       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        goto loop;
+               }
 
                if (counting) {
+                       mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                        spin_lock(&fs_info->balance_lock);
                        bctl->stat.expected++;
                        spin_unlock(&fs_info->balance_lock);
@@ -3348,6 +3377,7 @@ again:
                ret = btrfs_relocate_chunk(chunk_root,
                                           found_key.objectid,
                                           found_key.offset);
+               mutex_unlock(&fs_info->delete_unused_bgs_mutex);
                if (ret && ret != -ENOSPC)
                        goto error;
                if (ret == -ENOSPC) {
@@ -4087,11 +4117,16 @@ again:
        key.type = BTRFS_DEV_EXTENT_KEY;
 
        do {
+               mutex_lock(&root->fs_info->delete_unused_bgs_mutex);
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-               if (ret < 0)
+               if (ret < 0) {
+                       mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                        goto done;
+               }
 
                ret = btrfs_previous_item(root, path, 0, key.type);
+               if (ret)
+                       mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                if (ret < 0)
                        goto done;
                if (ret) {
@@ -4105,6 +4140,7 @@ again:
                btrfs_item_key_to_cpu(l, &key, path->slots[0]);
 
                if (key.objectid != device->devid) {
+                       mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                        btrfs_release_path(path);
                        break;
                }
@@ -4113,6 +4149,7 @@ again:
                length = btrfs_dev_extent_length(l, dev_extent);
 
                if (key.offset + length <= new_size) {
+                       mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                        btrfs_release_path(path);
                        break;
                }
@@ -4122,6 +4159,7 @@ again:
                btrfs_release_path(path);
 
                ret = btrfs_relocate_chunk(root, chunk_objectid, chunk_offset);
+               mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
                if (ret && ret != -ENOSPC)
                        goto done;
                if (ret == -ENOSPC)
@@ -5715,7 +5753,6 @@ static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio, int e
 static void btrfs_end_bio(struct bio *bio, int err)
 {
        struct btrfs_bio *bbio = bio->bi_private;
-       struct btrfs_device *dev = bbio->stripes[0].dev;
        int is_orig_bio = 0;
 
        if (err) {
@@ -5723,6 +5760,7 @@ static void btrfs_end_bio(struct bio *bio, int err)
                if (err == -EIO || err == -EREMOTEIO) {
                        unsigned int stripe_index =
                                btrfs_io_bio(bio)->stripe_index;
+                       struct btrfs_device *dev;
 
                        BUG_ON(stripe_index >= bbio->num_stripes);
                        dev = bbio->stripes[stripe_index].dev;
index dc10c9dd36c1a2ac6264ed21d3248e5f62f1e330..ddd5e94712904501db729c51b59de72cd88ddb5a 100644 (file)
@@ -1506,7 +1506,6 @@ static int __mark_caps_flushing(struct inode *inode,
 
        swap(cf, ci->i_prealloc_cap_flush);
        cf->caps = flushing;
-       cf->kick = false;
 
        spin_lock(&mdsc->cap_dirty_lock);
        list_del_init(&ci->i_dirty_item);
@@ -2123,8 +2122,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
 
 static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
                                struct ceph_mds_session *session,
-                               struct ceph_inode_info *ci,
-                               bool kick_all)
+                               struct ceph_inode_info *ci)
 {
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap *cap;
@@ -2150,9 +2148,7 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
 
                for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
                        cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       if (cf->tid < first_tid)
-                               continue;
-                       if (kick_all || cf->kick)
+                       if (cf->tid >= first_tid)
                                break;
                }
                if (!n) {
@@ -2161,7 +2157,6 @@ static int __kick_flushing_caps(struct ceph_mds_client *mdsc,
                }
 
                cf = rb_entry(n, struct ceph_cap_flush, i_node);
-               cf->kick = false;
 
                first_tid = cf->tid + 1;
 
@@ -2181,8 +2176,6 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
 {
        struct ceph_inode_info *ci;
        struct ceph_cap *cap;
-       struct ceph_cap_flush *cf;
-       struct rb_node *n;
 
        dout("early_kick_flushing_caps mds%d\n", session->s_mds);
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
@@ -2205,16 +2198,11 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
                if ((cap->issued & ci->i_flushing_caps) !=
                    ci->i_flushing_caps) {
                        spin_unlock(&ci->i_ceph_lock);
-                       if (!__kick_flushing_caps(mdsc, session, ci, true))
+                       if (!__kick_flushing_caps(mdsc, session, ci))
                                continue;
                        spin_lock(&ci->i_ceph_lock);
                }
 
-               for (n = rb_first(&ci->i_cap_flush_tree); n; n = rb_next(n)) {
-                       cf = rb_entry(n, struct ceph_cap_flush, i_node);
-                       cf->kick = true;
-               }
-
                spin_unlock(&ci->i_ceph_lock);
        }
 }
@@ -2228,7 +2216,7 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
 
        dout("kick_flushing_caps mds%d\n", session->s_mds);
        list_for_each_entry(ci, &session->s_cap_flushing, i_flushing_item) {
-               int delayed = __kick_flushing_caps(mdsc, session, ci, false);
+               int delayed = __kick_flushing_caps(mdsc, session, ci);
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
                        __cap_delay_requeue(mdsc, ci);
@@ -2261,7 +2249,7 @@ static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
 
                spin_unlock(&ci->i_ceph_lock);
 
-               delayed = __kick_flushing_caps(mdsc, session, ci, true);
+               delayed = __kick_flushing_caps(mdsc, session, ci);
                if (delayed) {
                        spin_lock(&ci->i_ceph_lock);
                        __cap_delay_requeue(mdsc, ci);
index 4347039ecc183d538c23f32019e5213da2ebf2f4..6706bde9ad1b1e16e6a283a83ea93c4f58b6b2aa 100644 (file)
@@ -287,7 +287,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
                return 0;
 
        spin_lock(&ctx->flc_lock);
-       list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
+       list_for_each_entry(lock, &ctx->flc_posix, fl_list) {
                ++seen_fcntl;
                if (seen_fcntl > num_fcntl_locks) {
                        err = -ENOSPC;
index 860cc016e70d4ff463c1f7845fc648eaf58269c4..2f2460d23a0600f8f9bf2e1cc4fe3b2286684356 100644 (file)
@@ -189,7 +189,6 @@ static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap)
 struct ceph_cap_flush {
        u64 tid;
        int caps;
-       bool kick;
        struct rb_node g_node; // global
        union {
                struct rb_node i_node; // inode
index 6b8e2f091f5b8fd71d63d545ea5fe9ae593d7688..48851f6ea6ecc9af8c54b9e664909c878dc26bb7 100644 (file)
@@ -896,6 +896,7 @@ COMPATIBLE_IOCTL(FIGETBSZ)
 /* 'X' - originally XFS but some now in the VFS */
 COMPATIBLE_IOCTL(FIFREEZE)
 COMPATIBLE_IOCTL(FITHAW)
+COMPATIBLE_IOCTL(FITRIM)
 COMPATIBLE_IOCTL(KDGETKEYCODE)
 COMPATIBLE_IOCTL(KDSETKEYCODE)
 COMPATIBLE_IOCTL(KDGKBTYPE)
index 4d6a30e76168c3f548ce48dbbb1428e0baf81d49..b863a09cd2f1e9b35d53bbf284e3eb3c3cbeb226 100644 (file)
@@ -115,7 +115,7 @@ void config_item_init_type_name(struct config_item *item,
                                const char *name,
                                struct config_item_type *type)
 {
-       config_item_set_name(item, name);
+       config_item_set_name(item, "%s", name);
        item->ci_type = type;
        config_item_init(item);
 }
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(config_item_init_type_name);
 void config_group_init_type_name(struct config_group *group, const char *name,
                         struct config_item_type *type)
 {
-       config_item_set_name(&group->cg_item, name);
+       config_item_set_name(&group->cg_item, "%s", name);
        group->cg_item.ci_type = type;
        config_group_init(group);
 }
index c3e21ccfc358b2da1170c15f09a5946afad0ff16..a7f77e1fa18c25e62e8de5f809389d041e59266e 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -319,6 +319,12 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh,
  * @vma: The virtual memory area where the fault occurred
  * @vmf: The description of the fault
  * @get_block: The filesystem method used to translate file offsets to blocks
+ * @complete_unwritten: The filesystem method used to convert unwritten blocks
+ *     to written so the data written to them is exposed. This is required for
+ *     required by write faults for filesystems that will return unwritten
+ *     extent mappings from @get_block, but it is optional for reads as
+ *     dax_insert_mapping() will always zero unwritten blocks. If the fs does
+ *     not support unwritten extents, the it should pass NULL.
  *
  * When a page fault occurs, filesystems may call this helper in their
  * fault handler for DAX files. __dax_fault() assumes the caller has done all
@@ -437,8 +443,12 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf,
         * as for normal BH based IO completions.
         */
        error = dax_insert_mapping(inode, &bh, vma, vmf);
-       if (buffer_unwritten(&bh))
-               complete_unwritten(&bh, !error);
+       if (buffer_unwritten(&bh)) {
+               if (complete_unwritten)
+                       complete_unwritten(&bh, !error);
+               else
+                       WARN_ON_ONCE(!(vmf->flags & FAULT_FLAG_WRITE));
+       }
 
  out:
        if (error == -ENOMEM)
index 7a3f3e5f9ceabfc4cad41a5d5478258f7e817dc1..9b5fe503f6cb6c8d76044bb8272084fdb0474c9b 100644 (file)
@@ -642,7 +642,7 @@ static inline bool fast_dput(struct dentry *dentry)
 
        /*
         * If we have a d_op->d_delete() operation, we sould not
-        * let the dentry count go to zero, so use "put__or_lock".
+        * let the dentry count go to zero, so use "put_or_lock".
         */
        if (unlikely(dentry->d_flags & DCACHE_OP_DELETE))
                return lockref_put_or_lock(&dentry->d_lockref);
@@ -697,7 +697,7 @@ static inline bool fast_dput(struct dentry *dentry)
         */
        smp_rmb();
        d_flags = ACCESS_ONCE(dentry->d_flags);
-       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST;
+       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_DISCONNECTED;
 
        /* Nothing to do? Dropping the reference was all we needed? */
        if (d_flags == (DCACHE_REFERENCED | DCACHE_LRU_LIST) && !d_unhashed(dentry))
@@ -776,6 +776,9 @@ repeat:
        if (unlikely(d_unhashed(dentry)))
                goto kill_it;
 
+       if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
+               goto kill_it;
+
        if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
                if (dentry->d_op->d_delete(dentry))
                        goto kill_it;
@@ -3439,22 +3442,15 @@ void __init vfs_caches_init_early(void)
        inode_init_early();
 }
 
-void __init vfs_caches_init(unsigned long mempages)
+void __init vfs_caches_init(void)
 {
-       unsigned long reserve;
-
-       /* Base hash sizes on available memory, with a reserve equal to
-           150% of current kernel size */
-
-       reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
-       mempages -= reserve;
-
        names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 
        dcache_init();
        inode_init();
-       files_init(mempages);
+       files_init();
+       files_maxfiles_init();
        mnt_init();
        bdev_cache_init();
        chrdev_init();
index 72afcc629d7b1fee2963fb90e1691a221eb77d8e..feef8a9c4de7cf09bcbc0effb45f83c207c9015b 100644 (file)
@@ -325,7 +325,6 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return rc;
 
        switch (cmd) {
-       case FITRIM:
        case FS_IOC32_GETFLAGS:
        case FS_IOC32_SETFLAGS:
        case FS_IOC32_GETVERSION:
index aadb7282883493597f8dae099f20c3e86694bea8..2553aa8b608d84d1673190ea634c5e84c86d9f0b 100644 (file)
@@ -504,7 +504,7 @@ __read_extent_tree_block(const char *function, unsigned int line,
        struct buffer_head              *bh;
        int                             err;
 
-       bh = sb_getblk(inode->i_sb, pblk);
+       bh = sb_getblk_gfp(inode->i_sb, pblk, __GFP_MOVABLE | GFP_NOFS);
        if (unlikely(!bh))
                return ERR_PTR(-ENOMEM);
 
@@ -1089,7 +1089,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                err = -EIO;
                goto cleanup;
        }
-       bh = sb_getblk(inode->i_sb, newblock);
+       bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS);
        if (unlikely(!bh)) {
                err = -ENOMEM;
                goto cleanup;
@@ -1283,7 +1283,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        if (newblock == 0)
                return err;
 
-       bh = sb_getblk(inode->i_sb, newblock);
+       bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS);
        if (unlikely(!bh))
                return -ENOMEM;
        lock_buffer(bh);
index 41f8e55afcd11491c5f25bf0989f74c12b9baf69..cecf9aa1081134d255455ee329a4e118b8355216 100644 (file)
@@ -1323,7 +1323,7 @@ static void ext4_da_page_release_reservation(struct page *page,
                                             unsigned int offset,
                                             unsigned int length)
 {
-       int to_release = 0;
+       int to_release = 0, contiguous_blks = 0;
        struct buffer_head *head, *bh;
        unsigned int curr_off = 0;
        struct inode *inode = page->mapping->host;
@@ -1344,14 +1344,23 @@ static void ext4_da_page_release_reservation(struct page *page,
 
                if ((offset <= curr_off) && (buffer_delay(bh))) {
                        to_release++;
+                       contiguous_blks++;
                        clear_buffer_delay(bh);
+               } else if (contiguous_blks) {
+                       lblk = page->index <<
+                              (PAGE_CACHE_SHIFT - inode->i_blkbits);
+                       lblk += (curr_off >> inode->i_blkbits) -
+                               contiguous_blks;
+                       ext4_es_remove_extent(inode, lblk, contiguous_blks);
+                       contiguous_blks = 0;
                }
                curr_off = next_off;
        } while ((bh = bh->b_this_page) != head);
 
-       if (to_release) {
+       if (contiguous_blks) {
                lblk = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-               ext4_es_remove_extent(inode, lblk, to_release);
+               lblk += (curr_off >> inode->i_blkbits) - contiguous_blks;
+               ext4_es_remove_extent(inode, lblk, contiguous_blks);
        }
 
        /* If we have released all the blocks belonging to a cluster, then we
@@ -4344,7 +4353,12 @@ static void ext4_update_other_inodes_time(struct super_block *sb,
        int inode_size = EXT4_INODE_SIZE(sb);
 
        oi.orig_ino = orig_ino;
-       ino = (orig_ino & ~(inodes_per_block - 1)) + 1;
+       /*
+        * Calculate the first inode in the inode table block.  Inode
+        * numbers are one-based.  That is, the first inode in a block
+        * (assuming 4k blocks and 256 byte inodes) is (n*16 + 1).
+        */
+       ino = ((orig_ino - 1) & ~(inodes_per_block - 1)) + 1;
        for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) {
                if (ino == orig_ino)
                        continue;
index cb8451246b30ae72c9787fe0e7326ac9c77b7b29..1346cfa355d0f167837a68d08325fa3529ebbc31 100644 (file)
@@ -755,7 +755,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return err;
        }
        case EXT4_IOC_MOVE_EXT:
-       case FITRIM:
        case EXT4_IOC_RESIZE_FS:
        case EXT4_IOC_PRECACHE_EXTENTS:
        case EXT4_IOC_SET_ENCRYPTION_POLICY:
index f6aedf88da437ee324c314bb1020baa51db0423c..34b610ea503053674b3b87ffd3503d6c641c573d 100644 (file)
@@ -4816,18 +4816,12 @@ do_more:
                /*
                 * blocks being freed are metadata. these blocks shouldn't
                 * be used until this transaction is committed
+                *
+                * We use __GFP_NOFAIL because ext4_free_blocks() is not allowed
+                * to fail.
                 */
-       retry:
-               new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS);
-               if (!new_entry) {
-                       /*
-                        * We use a retry loop because
-                        * ext4_free_blocks() is not allowed to fail.
-                        */
-                       cond_resched();
-                       congestion_wait(BLK_RW_ASYNC, HZ/50);
-                       goto retry;
-               }
+               new_entry = kmem_cache_alloc(ext4_free_data_cachep,
+                               GFP_NOFS|__GFP_NOFAIL);
                new_entry->efd_start_cluster = bit;
                new_entry->efd_group = block_group;
                new_entry->efd_count = count_clusters;
index b52374e4210221bc02c9cb3ad23f8027f21e77ad..6163ad21cb0ef6b184bdfceb700c1dfd89317590 100644 (file)
@@ -620,6 +620,7 @@ int ext4_ind_migrate(struct inode *inode)
        struct ext4_inode_info          *ei = EXT4_I(inode);
        struct ext4_extent              *ex;
        unsigned int                    i, len;
+       ext4_lblk_t                     start, end;
        ext4_fsblk_t                    blk;
        handle_t                        *handle;
        int                             ret;
@@ -633,6 +634,14 @@ int ext4_ind_migrate(struct inode *inode)
                                       EXT4_FEATURE_RO_COMPAT_BIGALLOC))
                return -EOPNOTSUPP;
 
+       /*
+        * In order to get correct extent info, force all delayed allocation
+        * blocks to be allocated, otherwise delayed allocation blocks may not
+        * be reflected and bypass the checks on extent header.
+        */
+       if (test_opt(inode->i_sb, DELALLOC))
+               ext4_alloc_da_blocks(inode);
+
        handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
@@ -650,11 +659,13 @@ int ext4_ind_migrate(struct inode *inode)
                goto errout;
        }
        if (eh->eh_entries == 0)
-               blk = len = 0;
+               blk = len = start = end = 0;
        else {
                len = le16_to_cpu(ex->ee_len);
                blk = ext4_ext_pblock(ex);
-               if (len > EXT4_NDIR_BLOCKS) {
+               start = le32_to_cpu(ex->ee_block);
+               end = start + len - 1;
+               if (end >= EXT4_NDIR_BLOCKS) {
                        ret = -EOPNOTSUPP;
                        goto errout;
                }
@@ -662,7 +673,7 @@ int ext4_ind_migrate(struct inode *inode)
 
        ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
        memset(ei->i_data, 0, sizeof(ei->i_data));
-       for (i=0; i < len; i++)
+       for (i = start; i <= end; i++)
                ei->i_data[i] = cpu_to_le32(blk++);
        ext4_mark_inode_dirty(handle, inode);
 errout:
index 9bedfa8dd3a5305d1407ce04c5fa3319a6882cd3..f71e19a9dd3c18fc6ee7b3bcb4f3da9c8b8c3d4c 100644 (file)
@@ -2072,8 +2072,6 @@ static int f2fs_set_data_page_dirty(struct page *page)
                return 1;
        }
 
-       mark_inode_dirty(inode);
-
        if (!PageDirty(page)) {
                __set_page_dirty_nobuffers(page);
                update_dirty_page(inode, page);
index ada2a3dd701ad5eb22add128a0d5e89ebb98383f..b0f38c3b37f4d5577551e6d517e801a6f644ac09 100644 (file)
@@ -1331,12 +1331,13 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
        if (ret)
                return ret;
 
-       if (f2fs_is_atomic_file(inode))
+       if (f2fs_is_atomic_file(inode)) {
+               clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
                commit_inmem_pages(inode, false);
+       }
 
        ret = f2fs_sync_file(filp, 0, LONG_MAX, 0);
        mnt_drop_write_file(filp);
-       clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
        return ret;
 }
 
@@ -1387,8 +1388,8 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
        f2fs_balance_fs(F2FS_I_SB(inode));
 
        if (f2fs_is_atomic_file(inode)) {
-               commit_inmem_pages(inode, false);
                clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
+               commit_inmem_pages(inode, false);
        }
 
        if (f2fs_is_volatile_file(inode))
index e1e73617d13b6cb5e1fca434e4ab823dfa534eca..22fb5ef37966210cb50f5b8679b7c661803128f9 100644 (file)
@@ -556,27 +556,39 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
        if (!fio.encrypted_page)
                goto put_out;
 
-       f2fs_submit_page_bio(&fio);
+       err = f2fs_submit_page_bio(&fio);
+       if (err)
+               goto put_page_out;
+
+       /* write page */
+       lock_page(fio.encrypted_page);
+
+       if (unlikely(!PageUptodate(fio.encrypted_page)))
+               goto put_page_out;
+       if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi)))
+               goto put_page_out;
+
+       set_page_dirty(fio.encrypted_page);
+       f2fs_wait_on_page_writeback(fio.encrypted_page, META);
+       if (clear_page_dirty_for_io(fio.encrypted_page))
+               dec_page_count(fio.sbi, F2FS_DIRTY_META);
+
+       set_page_writeback(fio.encrypted_page);
 
        /* allocate block address */
        f2fs_wait_on_page_writeback(dn.node_page, NODE);
-
        allocate_data_block(fio.sbi, NULL, fio.blk_addr,
                                        &fio.blk_addr, &sum, CURSEG_COLD_DATA);
-       dn.data_blkaddr = fio.blk_addr;
-
-       /* write page */
-       lock_page(fio.encrypted_page);
-       set_page_writeback(fio.encrypted_page);
        fio.rw = WRITE_SYNC;
        f2fs_submit_page_mbio(&fio);
 
+       dn.data_blkaddr = fio.blk_addr;
        set_data_blkaddr(&dn);
        f2fs_update_extent_cache(&dn);
        set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
        if (page->index == 0)
                set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
-
+put_page_out:
        f2fs_put_page(fio.encrypted_page, 1);
 put_out:
        f2fs_put_dnode(&dn);
@@ -605,8 +617,8 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
                        .page = page,
                        .encrypted_page = NULL,
                };
+               set_page_dirty(page);
                f2fs_wait_on_page_writeback(page, DATA);
-
                if (clear_page_dirty_for_io(page))
                        inode_dec_dirty_pages(inode);
                set_cold_data(page);
index 38e75fb1e48812b38d477a13a53f0469fb95bbd3..a13ffcc329923b85f6dee0064e56681bf8a1269c 100644 (file)
@@ -141,6 +141,8 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        kunmap_atomic(dst_addr);
        SetPageUptodate(page);
 no_update:
+       set_page_dirty(page);
+
        /* clear dirty state */
        dirty = clear_page_dirty_for_io(page);
 
index 1eb343768781f3c4c89e0f6ecc2694d9a4c61c75..61b97f9cb9f657961d7ce12a490d55ece03e18a4 100644 (file)
@@ -257,6 +257,7 @@ void commit_inmem_pages(struct inode *inode, bool abort)
                if (!abort) {
                        lock_page(cur->page);
                        if (cur->page->mapping == inode->i_mapping) {
+                               set_page_dirty(cur->page);
                                f2fs_wait_on_page_writeback(cur->page, DATA);
                                if (clear_page_dirty_for_io(cur->page))
                                        inode_dec_dirty_pages(inode);
index 7f9d407c759596f950335bd418ab0226f4a629f8..ad17e05ebf95f07888b15f2b09a7b37ac89b9710 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/hardirq.h>
 #include <linux/task_work.h>
 #include <linux/ima.h>
+#include <linux/swap.h>
 
 #include <linux/atomic.h>
 
@@ -308,19 +309,24 @@ void put_filp(struct file *file)
        }
 }
 
-void __init files_init(unsigned long mempages)
+void __init files_init(void)
 { 
-       unsigned long n;
-
        filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
                        SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       percpu_counter_init(&nr_files, 0, GFP_KERNEL);
+}
 
-       /*
-        * One file with associated inode and dcache is very roughly 1K.
-        * Per default don't use more than 10% of our memory for files. 
-        */ 
+/*
+ * One file with associated inode and dcache is very roughly 1K. Per default
+ * do not use more than 10% of our memory for files.
+ */
+void __init files_maxfiles_init(void)
+{
+       unsigned long n;
+       unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2;
+
+       memreserve = min(memreserve, totalram_pages - 1);
+       n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10;
 
-       n = (mempages * (PAGE_SIZE / 1024)) / 10;
        files_stat.max_files = max_t(unsigned long, n, NR_FILE);
-       percpu_counter_init(&nr_files, 0, GFP_KERNEL);
 } 
index f0520bcf209442914eff0ed60d380fb3d2c66402..518c6294bf6c0ef965e9f56baa4e11d2eccc0165 100644 (file)
@@ -702,6 +702,7 @@ void wbc_account_io(struct writeback_control *wbc, struct page *page,
        else
                wbc->wb_tcand_bytes -= min(bytes, wbc->wb_tcand_bytes);
 }
+EXPORT_SYMBOL_GPL(wbc_account_io);
 
 /**
  * inode_congested - test whether an inode is congested
index 80cc1b35d46043c16bc456e0cadf61e76c281d52..ebb5e37455a07acd86f5fbf1b76d474e99b937fb 100644 (file)
@@ -2246,7 +2246,15 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 
                        err = -EINVAL;
                        if (old) {
-                               struct fuse_dev *fud = fuse_get_dev(old);
+                               struct fuse_dev *fud = NULL;
+
+                               /*
+                                * Check against file->f_op because CUSE
+                                * uses the same ioctl handler.
+                                */
+                               if (old->f_op == file->f_op &&
+                                   old->f_cred->user_ns == file->f_cred->user_ns)
+                                       fud = fuse_get_dev(old);
 
                                if (fud) {
                                        mutex_lock(&fuse_mutex);
index f005046e1591eaa343a4eba0e34b1bbc1e31b4f8..d6a4b55d2ab0512aa34221564f7cff421be0e152 100644 (file)
@@ -484,3 +484,98 @@ struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *a
        a->btree.first_free = cpu_to_le16(8);
        return a;
 }
+
+static unsigned find_run(__le32 *bmp, unsigned *idx)
+{
+       unsigned len;
+       while (tstbits(bmp, *idx, 1)) {
+               (*idx)++;
+               if (unlikely(*idx >= 0x4000))
+                       return 0;
+       }
+       len = 1;
+       while (!tstbits(bmp, *idx + len, 1))
+               len++;
+       return len;
+}
+
+static int do_trim(struct super_block *s, secno start, unsigned len, secno limit_start, secno limit_end, unsigned minlen, unsigned *result)
+{
+       int err;
+       secno end;
+       if (fatal_signal_pending(current))
+               return -EINTR;
+       end = start + len;
+       if (start < limit_start)
+               start = limit_start;
+       if (end > limit_end)
+               end = limit_end;
+       if (start >= end)
+               return 0;
+       if (end - start < minlen)
+               return 0;
+       err = sb_issue_discard(s, start, end - start, GFP_NOFS, 0);
+       if (err)
+               return err;
+       *result += end - start;
+       return 0;
+}
+
+int hpfs_trim_fs(struct super_block *s, u64 start, u64 end, u64 minlen, unsigned *result)
+{
+       int err = 0;
+       struct hpfs_sb_info *sbi = hpfs_sb(s);
+       unsigned idx, len, start_bmp, end_bmp;
+       __le32 *bmp;
+       struct quad_buffer_head qbh;
+
+       *result = 0;
+       if (!end || end > sbi->sb_fs_size)
+               end = sbi->sb_fs_size;
+       if (start >= sbi->sb_fs_size)
+               return 0;
+       if (minlen > 0x4000)
+               return 0;
+       if (start < sbi->sb_dirband_start + sbi->sb_dirband_size && end > sbi->sb_dirband_start) {
+               hpfs_lock(s);
+               if (s->s_flags & MS_RDONLY) {
+                       err = -EROFS;
+                       goto unlock_1;
+               }
+               if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
+                       err = -EIO;
+                       goto unlock_1;
+               }
+               idx = 0;
+               while ((len = find_run(bmp, &idx)) && !err) {
+                       err = do_trim(s, sbi->sb_dirband_start + idx * 4, len * 4, start, end, minlen, result);
+                       idx += len;
+               }
+               hpfs_brelse4(&qbh);
+unlock_1:
+               hpfs_unlock(s);
+       }
+       start_bmp = start >> 14;
+       end_bmp = (end + 0x3fff) >> 14;
+       while (start_bmp < end_bmp && !err) {
+               hpfs_lock(s);
+               if (s->s_flags & MS_RDONLY) {
+                       err = -EROFS;
+                       goto unlock_2;
+               }
+               if (!(bmp = hpfs_map_bitmap(s, start_bmp, &qbh, "trim"))) {
+                       err = -EIO;
+                       goto unlock_2;
+               }
+               idx = 0;
+               while ((len = find_run(bmp, &idx)) && !err) {
+                       err = do_trim(s, (start_bmp << 14) + idx, len, start, end, minlen, result);
+                       idx += len;
+               }
+               hpfs_brelse4(&qbh);
+unlock_2:
+               hpfs_unlock(s);
+               start_bmp++;
+       }
+       return err;
+}
index 2a8e07425de01eab5f8a40b5505268b4cc6e2014..dc540bfcee1d8e7842b6b0f0ca402214f9bf5609 100644 (file)
@@ -327,4 +327,5 @@ const struct file_operations hpfs_dir_ops =
        .iterate        = hpfs_readdir,
        .release        = hpfs_dir_release,
        .fsync          = hpfs_file_fsync,
+       .unlocked_ioctl = hpfs_ioctl,
 };
index 6d8cfe9b52d611b7dadbfa1a38ec7cf3c3b3671c..7ca28d604bf7679b3d112a227c196da04f1734e2 100644 (file)
@@ -203,6 +203,7 @@ const struct file_operations hpfs_file_ops =
        .release        = hpfs_file_release,
        .fsync          = hpfs_file_fsync,
        .splice_read    = generic_file_splice_read,
+       .unlocked_ioctl = hpfs_ioctl,
 };
 
 const struct inode_operations hpfs_file_iops =
index bb04b58d1d698486ec31c4fd3e91dab567dbb517..c4867b5116ddf72b3617c8946c7d6b27dd03cd87 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
 #include <asm/unaligned.h>
 
 #include "hpfs.h"
@@ -200,6 +202,7 @@ void hpfs_free_dnode(struct super_block *, secno);
 struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *);
 struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **);
 struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **);
+int hpfs_trim_fs(struct super_block *, u64, u64, u64, unsigned *);
 
 /* anode.c */
 
@@ -318,6 +321,7 @@ __printf(2, 3)
 void hpfs_error(struct super_block *, const char *, ...);
 int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
 unsigned hpfs_get_free_dnodes(struct super_block *);
+long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg);
 
 /*
  * local time (HPFS) to GMT (Unix)
index 7cd00d3a7c9b742a86d9fdb16a36b805952b2cf9..68a9bed056284c5a4304c10d607f78f1d4638538 100644 (file)
@@ -52,17 +52,20 @@ static void unmark_dirty(struct super_block *s)
 }
 
 /* Filesystem error... */
-static char err_buf[1024];
-
 void hpfs_error(struct super_block *s, const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
 
        va_start(args, fmt);
-       vsnprintf(err_buf, sizeof(err_buf), fmt, args);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       pr_err("filesystem error: %pV", &vaf);
+
        va_end(args);
 
-       pr_err("filesystem error: %s", err_buf);
        if (!hpfs_sb(s)->sb_was_error) {
                if (hpfs_sb(s)->sb_err == 2) {
                        pr_cont("; crashing the system because you wanted it\n");
@@ -196,12 +199,39 @@ static int hpfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
+
+long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+       switch (cmd) {
+               case FITRIM: {
+                       struct fstrim_range range;
+                       secno n_trimmed;
+                       int r;
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+                       if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range)))
+                               return -EFAULT;
+                       r = hpfs_trim_fs(file_inode(file)->i_sb, range.start >> 9, (range.start + range.len) >> 9, (range.minlen + 511) >> 9, &n_trimmed);
+                       if (r)
+                               return r;
+                       range.len = (u64)n_trimmed << 9;
+                       if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range)))
+                               return -EFAULT;
+                       return 0;
+               }
+               default: {
+                       return -ENOIOCTLCMD;
+               }
+       }
+}
+
+
 static struct kmem_cache * hpfs_inode_cachep;
 
 static struct inode *hpfs_alloc_inode(struct super_block *sb)
 {
        struct hpfs_inode_info *ei;
-       ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS);
+       ei = kmem_cache_alloc(hpfs_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
        ei->vfs_inode.i_version = 1;
@@ -424,11 +454,14 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
        int o;
        struct hpfs_sb_info *sbi = hpfs_sb(s);
        char *new_opts = kstrdup(data, GFP_KERNEL);
-       
+
+       if (!new_opts)
+               return -ENOMEM;
+
        sync_filesystem(s);
 
        *flags |= MS_NOATIME;
-       
+
        hpfs_lock(s);
        uid = sbi->sb_uid; gid = sbi->sb_gid;
        umask = 0777 & ~sbi->sb_mode;
index 0cf74df68617b8738342a5f7be7992ccc596bf0a..973c24ce59ad3ef1b62ff3ce00113d7d85cedb68 100644 (file)
@@ -1010,6 +1010,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
        inode = hugetlbfs_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0);
        if (!inode)
                goto out_dentry;
+       if (creat_flags == HUGETLB_SHMFS_INODE)
+               inode->i_flags |= S_PRIVATE;
 
        file = ERR_PTR(-ENOMEM);
        if (hugetlb_reserve_pages(inode, 0,
index e98d39d75cf41a3f63c889958f87804dbb6aacf2..b9dc23cd04f20626269a32b820881c8bdc1a8a82 100644 (file)
@@ -76,7 +76,7 @@ static int jfs_open(struct inode *inode, struct file *file)
                if (ji->active_ag == -1) {
                        struct jfs_sb_info *jfs_sb = JFS_SBI(inode->i_sb);
                        ji->active_ag = BLKTOAG(addressPXD(&ji->ixpxd), jfs_sb);
-                       atomic_inc( &jfs_sb->bmap->db_active[ji->active_ag]);
+                       atomic_inc(&jfs_sb->bmap->db_active[ji->active_ag]);
                }
                spin_unlock_irq(&ji->ag_lock);
        }
index 6f1cb2b5ee285dd50622f719296fe71284d5f826..41aa3ca6a6a4995104d12f38cc5945ebb63a0f7d 100644 (file)
@@ -134,11 +134,11 @@ int jfs_write_inode(struct inode *inode, struct writeback_control *wbc)
         * It has been committed since the last change, but was still
         * on the dirty inode list.
         */
-        if (!test_cflag(COMMIT_Dirty, inode)) {
+       if (!test_cflag(COMMIT_Dirty, inode)) {
                /* Make sure committed changes hit the disk */
                jfs_flush_journal(JFS_SBI(inode->i_sb)->log, wait);
                return 0;
-        }
+       }
 
        if (jfs_commit_inode(inode, wait)) {
                jfs_err("jfs_write_inode: jfs_commit_inode failed!");
index 93a1232894f60a07abd8c6b1cdbbb6239270ed27..8db8b7d61e4048cf97ac289f263bc78c8685294d 100644 (file)
@@ -180,9 +180,6 @@ long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        case JFS_IOC_SETFLAGS32:
                cmd = JFS_IOC_SETFLAGS;
                break;
-       case FITRIM:
-               cmd = FITRIM;
-               break;
        }
        return jfs_ioctl(filp, cmd, arg);
 }
index e33be921aa41b5ae56a4054605aaeea5b8065987..a5ac97b9a933afcc8e91673b599f149e92184f16 100644 (file)
@@ -1160,7 +1160,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                rc = dtModify(tid, new_dir, &new_dname, &ino,
                              old_ip->i_ino, JFS_RENAME);
                if (rc)
-                       goto out4;
+                       goto out_tx;
                drop_nlink(new_ip);
                if (S_ISDIR(new_ip->i_mode)) {
                        drop_nlink(new_ip);
@@ -1185,7 +1185,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
                                txAbort(tid, 1);        /* Marks FS Dirty */
                                rc = new_size;
-                               goto out4;
+                               goto out_tx;
                        }
                        tblk = tid_to_tblock(tid);
                        tblk->xflag |= COMMIT_DELETE;
@@ -1203,7 +1203,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (rc) {
                        jfs_err("jfs_rename didn't expect dtSearch to fail "
                                "w/rc = %d", rc);
-                       goto out4;
+                       goto out_tx;
                }
 
                ino = old_ip->i_ino;
@@ -1211,7 +1211,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (rc) {
                        if (rc == -EIO)
                                jfs_err("jfs_rename: dtInsert returned -EIO");
-                       goto out4;
+                       goto out_tx;
                }
                if (S_ISDIR(old_ip->i_mode))
                        inc_nlink(new_dir);
@@ -1226,7 +1226,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
                        rc);
                txAbort(tid, 1);        /* Marks Filesystem dirty */
-               goto out4;
+               goto out_tx;
        }
        if (S_ISDIR(old_ip->i_mode)) {
                drop_nlink(old_dir);
@@ -1285,7 +1285,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        rc = txCommit(tid, ipcount, iplist, commit_flag);
 
-      out4:
+      out_tx:
        txEnd(tid);
        if (new_ip)
                mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
@@ -1308,13 +1308,6 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
        if (new_ip && (new_ip->i_nlink == 0))
                set_cflag(COMMIT_Nolink, new_ip);
-      out3:
-       free_UCSname(&new_dname);
-      out2:
-       free_UCSname(&old_dname);
-      out1:
-       if (new_ip && !S_ISDIR(new_ip->i_mode))
-               IWRITE_UNLOCK(new_ip);
        /*
         * Truncating the directory index table is not guaranteed.  It
         * may need to be done iteratively
@@ -1325,7 +1318,13 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
                clear_cflag(COMMIT_Stale, old_dir);
        }
-
+       if (new_ip && !S_ISDIR(new_ip->i_mode))
+               IWRITE_UNLOCK(new_ip);
+      out3:
+       free_UCSname(&new_dname);
+      out2:
+       free_UCSname(&old_dname);
+      out1:
        jfs_info("jfs_rename: returning %d", rc);
        return rc;
 }
index 653faabb07f46b70f4d414519ae6093e2d52e5cf..d3d558ba4da7966de9699aeb98b2630bd7c6854e 100644 (file)
@@ -862,12 +862,11 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
  * whether or not a lock was successfully freed by testing the return
  * value for -ENOENT.
  */
-static int flock_lock_file(struct file *filp, struct file_lock *request)
+static int flock_lock_inode(struct inode *inode, struct file_lock *request)
 {
        struct file_lock *new_fl = NULL;
        struct file_lock *fl;
        struct file_lock_context *ctx;
-       struct inode *inode = file_inode(filp);
        int error = 0;
        bool found = false;
        LIST_HEAD(dispose);
@@ -890,7 +889,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                goto find_conflict;
 
        list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
-               if (filp != fl->fl_file)
+               if (request->fl_file != fl->fl_file)
                        continue;
                if (request->fl_type == fl->fl_type)
                        goto out;
@@ -1164,20 +1163,19 @@ int posix_lock_file(struct file *filp, struct file_lock *fl,
 EXPORT_SYMBOL(posix_lock_file);
 
 /**
- * posix_lock_file_wait - Apply a POSIX-style lock to a file
- * @filp: The file to apply the lock to
+ * posix_lock_inode_wait - Apply a POSIX-style lock to a file
+ * @inode: inode of file to which lock request should be applied
  * @fl: The lock to be applied
  *
- * Add a POSIX style lock to a file.
- * We merge adjacent & overlapping locks whenever possible.
- * POSIX locks are sorted by owner task, then by starting address
+ * Variant of posix_lock_file_wait that does not take a filp, and so can be
+ * used after the filp has already been torn down.
  */
-int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
+int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 {
        int error;
        might_sleep ();
        for (;;) {
-               error = posix_lock_file(filp, fl, NULL);
+               error = __posix_lock_file(inode, fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
                error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1189,7 +1187,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
        }
        return error;
 }
-EXPORT_SYMBOL(posix_lock_file_wait);
+EXPORT_SYMBOL(posix_lock_inode_wait);
 
 /**
  * locks_mandatory_locked - Check for an active lock
@@ -1851,18 +1849,18 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 }
 
 /**
- * flock_lock_file_wait - Apply a FLOCK-style lock to a file
- * @filp: The file to apply the lock to
+ * flock_lock_inode_wait - Apply a FLOCK-style lock to a file
+ * @inode: inode of the file to apply to
  * @fl: The lock to be applied
  *
- * Add a FLOCK style lock to a file.
+ * Apply a FLOCK style lock request to an inode.
  */
-int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
+int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 {
        int error;
        might_sleep();
        for (;;) {
-               error = flock_lock_file(filp, fl);
+               error = flock_lock_inode(inode, fl);
                if (error != FILE_LOCK_DEFERRED)
                        break;
                error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1874,8 +1872,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
        }
        return error;
 }
-
-EXPORT_SYMBOL(flock_lock_file_wait);
+EXPORT_SYMBOL(flock_lock_inode_wait);
 
 /**
  *     sys_flock: - flock() system call.
@@ -2401,7 +2398,8 @@ locks_remove_flock(struct file *filp)
                .fl_type = F_UNLCK,
                .fl_end = OFFSET_MAX,
        };
-       struct file_lock_context *flctx = file_inode(filp)->i_flctx;
+       struct inode *inode = file_inode(filp);
+       struct file_lock_context *flctx = inode->i_flctx;
 
        if (list_empty(&flctx->flc_flock))
                return;
@@ -2409,7 +2407,7 @@ locks_remove_flock(struct file *filp)
        if (filp->f_op->flock)
                filp->f_op->flock(filp, F_SETLKW, &fl);
        else
-               flock_lock_file(filp, &fl);
+               flock_lock_inode(inode, &fl);
 
        if (fl.fl_ops && fl.fl_ops->fl_release_private)
                fl.fl_ops->fl_release_private(&fl);
index ae4e4c18b2ac0b2c366f893f7ffa4d898446c0f7..1c2105ed20c5ef4fb390878fb5442943ceec29ae 100644 (file)
@@ -879,7 +879,7 @@ static inline int may_follow_link(struct nameidata *nd)
                return 0;
 
        /* Allowed if parent directory not sticky and world-writable. */
-       parent = nd->path.dentry->d_inode;
+       parent = nd->inode;
        if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
                return 0;
 
@@ -1954,8 +1954,13 @@ OK:
                                continue;
                        }
                }
-               if (unlikely(!d_can_lookup(nd->path.dentry)))
+               if (unlikely(!d_can_lookup(nd->path.dentry))) {
+                       if (nd->flags & LOOKUP_RCU) {
+                               if (unlazy_walk(nd, NULL, 0))
+                                       return -ECHILD;
+                       }
                        return -ENOTDIR;
+               }
        }
 }
 
index c7cb8a526c05fbaa5ba18934cd04eda1eb2a6e60..2b8aa15fd6dfa755368ddf21136eaab5192f1e28 100644 (file)
@@ -1361,6 +1361,36 @@ enum umount_tree_flags {
        UMOUNT_PROPAGATE = 2,
        UMOUNT_CONNECTED = 4,
 };
+
+static bool disconnect_mount(struct mount *mnt, enum umount_tree_flags how)
+{
+       /* Leaving mounts connected is only valid for lazy umounts */
+       if (how & UMOUNT_SYNC)
+               return true;
+
+       /* A mount without a parent has nothing to be connected to */
+       if (!mnt_has_parent(mnt))
+               return true;
+
+       /* Because the reference counting rules change when mounts are
+        * unmounted and connected, umounted mounts may not be
+        * connected to mounted mounts.
+        */
+       if (!(mnt->mnt_parent->mnt.mnt_flags & MNT_UMOUNT))
+               return true;
+
+       /* Has it been requested that the mount remain connected? */
+       if (how & UMOUNT_CONNECTED)
+               return false;
+
+       /* Is the mount locked such that it needs to remain connected? */
+       if (IS_MNT_LOCKED(mnt))
+               return false;
+
+       /* By default disconnect the mount */
+       return true;
+}
+
 /*
  * mount_lock must be held
  * namespace_sem must be held for write
@@ -1398,10 +1428,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
                if (how & UMOUNT_SYNC)
                        p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
 
-               disconnect = !(((how & UMOUNT_CONNECTED) &&
-                               mnt_has_parent(p) &&
-                               (p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) ||
-                              IS_MNT_LOCKED_AND_LAZY(p));
+               disconnect = disconnect_mount(p, how);
 
                pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
                                 disconnect ? &unmounted : NULL);
@@ -1538,11 +1565,8 @@ void __detach_mounts(struct dentry *dentry)
        while (!hlist_empty(&mp->m_list)) {
                mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
                if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
-                       struct mount *p, *tmp;
-                       list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts,  mnt_child) {
-                               hlist_add_head(&p->mnt_umount.s_list, &unmounted);
-                               umount_mnt(p);
-                       }
+                       hlist_add_head(&mnt->mnt_umount.s_list, &unmounted);
+                       umount_mnt(mnt);
                }
                else umount_tree(mnt, UMOUNT_CONNECTED);
        }
index ecebb406cc1aec554ce780f2c3680eddc351e8da..4a90c9bb31357305ed6f38166bb0e9afabaae953 100644 (file)
@@ -775,7 +775,7 @@ static int nfs_init_server(struct nfs_server *server,
        server->options = data->options;
        server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
                NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
-               NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME|NFS_CAP_CHANGE_ATTR;
+               NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
 
        if (data->rsize)
                server->rsize = nfs_block_size(data->rsize, NULL);
index c12951b9551eab8b0394ed2aa218cf15ce6f2c39..b3289d701eea21623f4081fee1b2807e3e2f4b3a 100644 (file)
@@ -1852,7 +1852,7 @@ ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args,
        struct nfs42_layoutstat_devinfo *devinfo;
        int i;
 
-       for (i = 0; i <= FF_LAYOUT_MIRROR_COUNT(pls); i++) {
+       for (i = 0; i < FF_LAYOUT_MIRROR_COUNT(pls); i++) {
                if (*dev_count >= dev_limit)
                        break;
                mirror = FF_LAYOUT_COMP(pls, i);
index b77b328a06d74f0124d2a65b51fac0fc21fbd692..0adc7d245b3dd838e32371920e23d9dda5071ee0 100644 (file)
@@ -442,8 +442,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
                if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        inode->i_version = fattr->change_attr;
-               else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
-                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
+               else
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
+                               | NFS_INO_REVAL_PAGECACHE);
                if (fattr->valid & NFS_ATTR_FATTR_SIZE)
                        inode->i_size = nfs_size_to_loff_t(fattr->size);
                else
@@ -1244,9 +1245,11 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
                cur_size = i_size_read(inode);
                new_isize = nfs_size_to_loff_t(fattr->size);
-               if (cur_size != new_isize && nfsi->nrequests == 0)
+               if (cur_size != new_isize)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
        }
+       if (nfsi->nrequests != 0)
+               invalid &= ~NFS_INO_REVAL_PAGECACHE;
 
        /* Have any file permissions changed? */
        if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
@@ -1684,13 +1687,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        invalid |= NFS_INO_INVALID_ATTR
                                | NFS_INO_INVALID_DATA
                                | NFS_INO_INVALID_ACCESS
-                               | NFS_INO_INVALID_ACL
-                               | NFS_INO_REVAL_PAGECACHE;
+                               | NFS_INO_INVALID_ACL;
                        if (S_ISDIR(inode->i_mode))
                                nfs_force_lookup_revalidate(inode);
                        inode->i_version = fattr->change_attr;
                }
-       } else if (server->caps & NFS_CAP_CHANGE_ATTR)
+       } else
                nfsi->cache_validity |= save_cache_validity;
 
        if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
@@ -1717,7 +1719,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        if ((nfsi->nrequests == 0) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
-                               invalid &= ~NFS_INO_REVAL_PAGECACHE;
                        }
                        dprintk("NFS: isize change on server for file %s/%ld "
                                        "(%Ld to %Ld)\n",
index 7e3c4604bea8a6e6e92906b6c2096adb6df5ca3f..9b372b845f6a6ff06a4a035e2f6799d7d29cd8f7 100644 (file)
@@ -296,6 +296,22 @@ extern struct rpc_procinfo nfs4_procedures[];
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags);
+static inline struct nfs4_label *
+nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
+{
+       if (!dst || !src)
+               return NULL;
+
+       if (src->len > NFS4_MAXLABELLEN)
+               return NULL;
+
+       dst->lfs = src->lfs;
+       dst->pi = src->pi;
+       dst->len = src->len;
+       memcpy(dst->label, src->label, src->len);
+
+       return dst;
+}
 static inline void nfs4_label_free(struct nfs4_label *label)
 {
        if (label) {
@@ -316,6 +332,11 @@ static inline void nfs4_label_free(void *label) {}
 static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
 {
 }
+static inline struct nfs4_label *
+nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
+{
+       return NULL;
+}
 #endif /* CONFIG_NFS_V4_SECURITY_LABEL */
 
 /* proc.c */
index f486b80f927ab7204159852a9740900a6c73aec6..d731bbf974aaf1d4bf695c2cb57a99cc586e0258 100644 (file)
@@ -135,7 +135,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
        return err;
 }
 
-loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
 {
        struct inode *inode = file_inode(filep);
        struct nfs42_seek_args args = {
@@ -171,6 +171,23 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
        return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
 }
 
+loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+{
+       struct nfs_server *server = NFS_SERVER(file_inode(filep));
+       struct nfs4_exception exception = { };
+       int err;
+
+       do {
+               err = _nfs42_proc_llseek(filep, offset, whence);
+               if (err == -ENOTSUPP)
+                       return -EOPNOTSUPP;
+               err = nfs4_handle_exception(server, err, &exception);
+       } while (exception.retry);
+
+       return err;
+}
+
+
 static void
 nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
 {
index 6f228b5af819ea576240c40869c1da74d823e460..3acb1eb72930c40828bab90aeb27a3918f71138d 100644 (file)
@@ -467,7 +467,10 @@ static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
 
 static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
 {
-       do_renew_lease(server->nfs_client, timestamp);
+       struct nfs_client *clp = server->nfs_client;
+
+       if (!nfs4_has_session(clp))
+               do_renew_lease(clp, timestamp);
 }
 
 struct nfs4_call_sync_data {
@@ -616,8 +619,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
                clp = session->clp;
                do_renew_lease(clp, res->sr_timestamp);
                /* Check sequence flags */
-               if (res->sr_status_flags != 0)
-                       nfs4_schedule_lease_recovery(clp);
+               nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
                nfs41_update_target_slotid(slot->table, slot, res);
                break;
        case 1:
@@ -910,6 +912,7 @@ struct nfs4_opendata {
        struct nfs_open_confirmres c_res;
        struct nfs4_string owner_name;
        struct nfs4_string group_name;
+       struct nfs4_label *a_label;
        struct nfs_fattr f_attr;
        struct nfs4_label *f_label;
        struct dentry *dir;
@@ -1013,6 +1016,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        if (IS_ERR(p->f_label))
                goto err_free_p;
 
+       p->a_label = nfs4_label_alloc(server, gfp_mask);
+       if (IS_ERR(p->a_label))
+               goto err_free_f;
+
        alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
        p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask);
        if (IS_ERR(p->o_arg.seqid))
@@ -1041,7 +1048,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.server = server;
        p->o_arg.bitmask = nfs4_bitmask(server, label);
        p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
-       p->o_arg.label = label;
+       p->o_arg.label = nfs4_label_copy(p->a_label, label);
        p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
        switch (p->o_arg.claim) {
        case NFS4_OPEN_CLAIM_NULL:
@@ -1074,6 +1081,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        return p;
 
 err_free_label:
+       nfs4_label_free(p->a_label);
+err_free_f:
        nfs4_label_free(p->f_label);
 err_free_p:
        kfree(p);
@@ -1093,6 +1102,7 @@ static void nfs4_opendata_free(struct kref *kref)
                nfs4_put_open_state(p->state);
        nfs4_put_state_owner(p->owner);
 
+       nfs4_label_free(p->a_label);
        nfs4_label_free(p->f_label);
 
        dput(p->dir);
@@ -1198,12 +1208,15 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state,
 
 static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
 {
+       if (!(state->n_wronly || state->n_rdonly || state->n_rdwr))
+               return;
        if (state->n_wronly)
                set_bit(NFS_O_WRONLY_STATE, &state->flags);
        if (state->n_rdonly)
                set_bit(NFS_O_RDONLY_STATE, &state->flags);
        if (state->n_rdwr)
                set_bit(NFS_O_RDWR_STATE, &state->flags);
+       set_bit(NFS_OPEN_STATE, &state->flags);
 }
 
 static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
@@ -5439,15 +5452,15 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *
        return err;
 }
 
-static int do_vfs_lock(struct file *file, struct file_lock *fl)
+static int do_vfs_lock(struct inode *inode, struct file_lock *fl)
 {
        int res = 0;
        switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
                case FL_POSIX:
-                       res = posix_lock_file_wait(file, fl);
+                       res = posix_lock_inode_wait(inode, fl);
                        break;
                case FL_FLOCK:
-                       res = flock_lock_file_wait(file, fl);
+                       res = flock_lock_inode_wait(inode, fl);
                        break;
                default:
                        BUG();
@@ -5484,7 +5497,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
        atomic_inc(&lsp->ls_count);
        /* Ensure we don't close file until we're done freeing locks! */
        p->ctx = get_nfs_open_context(ctx);
-       get_file(fl->fl_file);
        memcpy(&p->fl, fl, sizeof(p->fl));
        p->server = NFS_SERVER(inode);
        return p;
@@ -5496,7 +5508,6 @@ static void nfs4_locku_release_calldata(void *data)
        nfs_free_seqid(calldata->arg.seqid);
        nfs4_put_lock_state(calldata->lsp);
        put_nfs_open_context(calldata->ctx);
-       fput(calldata->fl.fl_file);
        kfree(calldata);
 }
 
@@ -5509,7 +5520,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
        switch (task->tk_status) {
                case 0:
                        renew_lease(calldata->server, calldata->timestamp);
-                       do_vfs_lock(calldata->fl.fl_file, &calldata->fl);
+                       do_vfs_lock(calldata->lsp->ls_state->inode, &calldata->fl);
                        if (nfs4_update_lock_stateid(calldata->lsp,
                                        &calldata->res.stateid))
                                break;
@@ -5617,7 +5628,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        mutex_lock(&sp->so_delegreturn_mutex);
        /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
        down_read(&nfsi->rwsem);
-       if (do_vfs_lock(request->fl_file, request) == -ENOENT) {
+       if (do_vfs_lock(inode, request) == -ENOENT) {
                up_read(&nfsi->rwsem);
                mutex_unlock(&sp->so_delegreturn_mutex);
                goto out;
@@ -5758,7 +5769,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
                                data->timestamp);
                if (data->arg.new_lock) {
                        data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
-                       if (do_vfs_lock(data->fl.fl_file, &data->fl) < 0) {
+                       if (do_vfs_lock(lsp->ls_state->inode, &data->fl) < 0) {
                                rpc_restart_call_prepare(task);
                                break;
                        }
@@ -6000,7 +6011,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
        if (status != 0)
                goto out;
        request->fl_flags |= FL_ACCESS;
-       status = do_vfs_lock(request->fl_file, request);
+       status = do_vfs_lock(state->inode, request);
        if (status < 0)
                goto out;
        down_read(&nfsi->rwsem);
@@ -6008,7 +6019,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
                /* Yes: cache locks! */
                /* ...but avoid races with delegation recall... */
                request->fl_flags = fl_flags & ~FL_SLEEP;
-               status = do_vfs_lock(request->fl_file, request);
+               status = do_vfs_lock(state->inode, request);
                up_read(&nfsi->rwsem);
                goto out;
        }
@@ -7573,13 +7584,8 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
                goto out;
        }
        ret = rpc_wait_for_completion_task(task);
-       if (!ret) {
-               struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
-
-               if (task->tk_status == 0)
-                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
+       if (!ret)
                ret = task->tk_status;
-       }
        rpc_put_task(task);
 out:
        dprintk("<-- %s status=%d\n", __func__, ret);
@@ -7967,16 +7973,17 @@ static void nfs4_layoutreturn_release(void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
        struct pnfs_layout_hdr *lo = lrp->args.layout;
+       LIST_HEAD(freeme);
 
        dprintk("--> %s\n", __func__);
        spin_lock(&lo->plh_inode->i_lock);
        if (lrp->res.lrs_present)
                pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+       pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
        pnfs_clear_layoutreturn_waitbit(lo);
-       clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
-       rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
        lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
+       pnfs_free_lseg_list(&freeme);
        pnfs_put_layout_hdr(lrp->args.layout);
        nfs_iput_and_deactive(lrp->inode);
        kfree(calldata);
@@ -8590,7 +8597,6 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .minor_version = 0,
        .init_caps = NFS_CAP_READDIRPLUS
                | NFS_CAP_ATOMIC_OPEN
-               | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK,
        .init_client = nfs40_init_client,
        .shutdown_client = nfs40_shutdown_client,
@@ -8616,7 +8622,6 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
        .init_caps = NFS_CAP_READDIRPLUS
                | NFS_CAP_ATOMIC_OPEN
-               | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
@@ -8639,7 +8644,6 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
        .minor_version = 2,
        .init_caps = NFS_CAP_READDIRPLUS
                | NFS_CAP_ATOMIC_OPEN
-               | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1
index 605840dc89cf9e28c173659af201aab109f9328d..f2e2ad8944617f679a4a85934f6a276d3665229d 100644 (file)
@@ -2191,25 +2191,35 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp)
        }
 }
 
-static void nfs41_handle_state_revoked(struct nfs_client *clp)
+static void nfs41_handle_all_state_revoked(struct nfs_client *clp)
 {
        nfs4_reset_all_state(clp);
        dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
 }
 
+static void nfs41_handle_some_state_revoked(struct nfs_client *clp)
+{
+       nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
+       nfs4_schedule_state_manager(clp);
+
+       dprintk("%s: state revoked on server %s\n", __func__, clp->cl_hostname);
+}
+
 static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
 {
-       /* This will need to handle layouts too */
-       nfs_expire_all_delegations(clp);
+       /* FIXME: For now, we destroy all layouts. */
+       pnfs_destroy_all_layouts(clp);
+       /* FIXME: For now, we test all delegations+open state+locks. */
+       nfs41_handle_some_state_revoked(clp);
        dprintk("%s: Recallable state revoked on server %s!\n", __func__,
                        clp->cl_hostname);
 }
 
 static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
 {
-       nfs_expire_all_delegations(clp);
-       if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
-               nfs4_schedule_state_manager(clp);
+       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+       nfs4_schedule_state_manager(clp);
+
        dprintk("%s: server %s declared a backchannel fault\n", __func__,
                        clp->cl_hostname);
 }
@@ -2231,10 +2241,11 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
 
        if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
                nfs41_handle_server_reboot(clp);
-       if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
-                           SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
+       if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED))
+               nfs41_handle_all_state_revoked(clp);
+       if (flags & (SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
                            SEQ4_STATUS_ADMIN_STATE_REVOKED))
-               nfs41_handle_state_revoked(clp);
+               nfs41_handle_some_state_revoked(clp);
        if (flags & SEQ4_STATUS_LEASE_MOVED)
                nfs4_schedule_lease_moved_recovery(clp);
        if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
index 1da68d3b1edabdb78c60527f502af5f40d6cf69b..4984bbe55ff1eed1623df2196bc0de0de41a4304 100644 (file)
@@ -1100,8 +1100,6 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
                mirror->pg_base = 0;
                mirror->pg_recoalesce = 0;
 
-               desc->pg_moreio = 0;
-
                while (!list_empty(&head)) {
                        struct nfs_page *req;
 
@@ -1109,8 +1107,11 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
                        nfs_list_remove_request(req);
                        if (__nfs_pageio_add_request(desc, req))
                                continue;
-                       if (desc->pg_error < 0)
+                       if (desc->pg_error < 0) {
+                               list_splice_tail(&head, &mirror->pg_list);
+                               mirror->pg_recoalesce = 1;
                                return 0;
+                       }
                        break;
                }
        } while (mirror->pg_recoalesce);
index 0ba9a02c95664960f8c0f46ea97249bd8653fe16..70bf706b10904e156affe9dd4bea2ec9a17776c5 100644 (file)
@@ -352,7 +352,7 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
 {
        struct pnfs_layout_segment *s;
 
-       if (!test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
+       if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
                return false;
 
        list_for_each_entry(s, &lo->plh_segs, pls_list)
@@ -362,6 +362,18 @@ pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
        return true;
 }
 
+static bool
+pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
+{
+       if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
+               return false;
+       lo->plh_return_iomode = 0;
+       lo->plh_block_lgets++;
+       pnfs_get_layout_hdr(lo);
+       clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
+       return true;
+}
+
 static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
                struct pnfs_layout_hdr *lo, struct inode *inode)
 {
@@ -372,17 +384,16 @@ static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
        if (pnfs_layout_need_return(lo, lseg)) {
                nfs4_stateid stateid;
                enum pnfs_iomode iomode;
+               bool send;
 
                stateid = lo->plh_stateid;
                iomode = lo->plh_return_iomode;
-               /* decreased in pnfs_send_layoutreturn() */
-               lo->plh_block_lgets++;
-               lo->plh_return_iomode = 0;
+               send = pnfs_prepare_layoutreturn(lo);
                spin_unlock(&inode->i_lock);
-               pnfs_get_layout_hdr(lo);
-
-               /* Send an async layoutreturn so we dont deadlock */
-               pnfs_send_layoutreturn(lo, stateid, iomode, false);
+               if (send) {
+                       /* Send an async layoutreturn so we dont deadlock */
+                       pnfs_send_layoutreturn(lo, stateid, iomode, false);
+               }
        } else
                spin_unlock(&inode->i_lock);
 }
@@ -411,6 +422,10 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
                pnfs_layoutreturn_before_put_lseg(lseg, lo, inode);
 
        if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
+               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
+                       spin_unlock(&inode->i_lock);
+                       return;
+               }
                pnfs_get_layout_hdr(lo);
                pnfs_layout_remove_lseg(lo, lseg);
                spin_unlock(&inode->i_lock);
@@ -451,6 +466,8 @@ pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg)
                test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
        if (atomic_dec_and_test(&lseg->pls_refcount)) {
                struct pnfs_layout_hdr *lo = lseg->pls_layout;
+               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
+                       return;
                pnfs_get_layout_hdr(lo);
                pnfs_layout_remove_lseg(lo, lseg);
                pnfs_free_lseg_async(lseg);
@@ -924,6 +941,7 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
        clear_bit_unlock(NFS_LAYOUT_RETURN, &lo->plh_flags);
        smp_mb__after_atomic();
        wake_up_bit(&lo->plh_flags, NFS_LAYOUT_RETURN);
+       rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
 }
 
 static int
@@ -978,6 +996,7 @@ _pnfs_return_layout(struct inode *ino)
        LIST_HEAD(tmp_list);
        nfs4_stateid stateid;
        int status = 0, empty;
+       bool send;
 
        dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino);
 
@@ -1007,17 +1026,18 @@ _pnfs_return_layout(struct inode *ino)
        /* Don't send a LAYOUTRETURN if list was initially empty */
        if (empty) {
                spin_unlock(&ino->i_lock);
-               pnfs_put_layout_hdr(lo);
                dprintk("NFS: %s no layout segments to return\n", __func__);
-               goto out;
+               goto out_put_layout_hdr;
        }
 
        set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
-       lo->plh_block_lgets++;
+       send = pnfs_prepare_layoutreturn(lo);
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
-
-       status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
+       if (send)
+               status = pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true);
+out_put_layout_hdr:
+       pnfs_put_layout_hdr(lo);
 out:
        dprintk("<-- %s status: %d\n", __func__, status);
        return status;
@@ -1097,13 +1117,9 @@ bool pnfs_roc(struct inode *ino)
 out_noroc:
        if (lo) {
                stateid = lo->plh_stateid;
-               layoutreturn =
-                       test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
-                                          &lo->plh_flags);
-               if (layoutreturn) {
-                       lo->plh_block_lgets++;
-                       pnfs_get_layout_hdr(lo);
-               }
+               if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+                                          &lo->plh_flags))
+                       layoutreturn = pnfs_prepare_layoutreturn(lo);
        }
        spin_unlock(&ino->i_lock);
        if (layoutreturn) {
@@ -1146,15 +1162,18 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
        struct pnfs_layout_segment *lseg;
        nfs4_stateid stateid;
        u32 current_seqid;
-       bool found = false, layoutreturn = false;
+       bool layoutreturn = false;
 
        spin_lock(&ino->i_lock);
-       list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
-               if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
-                       rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
-                       found = true;
-                       goto out;
-               }
+       list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list) {
+               if (!test_bit(NFS_LSEG_ROC, &lseg->pls_flags))
+                       continue;
+               if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags))
+                       continue;
+               rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
+               spin_unlock(&ino->i_lock);
+               return true;
+       }
        lo = nfsi->layout;
        current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
 
@@ -1162,23 +1181,19 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
         * a barrier, we choose the worst-case barrier.
         */
        *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
-out:
-       if (!found) {
-               stateid = lo->plh_stateid;
-               layoutreturn =
-                       test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
-                                          &lo->plh_flags);
-               if (layoutreturn) {
-                       lo->plh_block_lgets++;
-                       pnfs_get_layout_hdr(lo);
-               }
-       }
+       stateid = lo->plh_stateid;
+       if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+                                          &lo->plh_flags))
+               layoutreturn = pnfs_prepare_layoutreturn(lo);
+       if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
+               rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
+
        spin_unlock(&ino->i_lock);
        if (layoutreturn) {
-               rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
                pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, false);
+               return true;
        }
-       return found;
+       return false;
 }
 
 /*
@@ -1695,7 +1710,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
        spin_lock(&inode->i_lock);
        /* set failure bit so that pnfs path will be retried later */
        pnfs_layout_set_fail_bit(lo, iomode);
-       set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
        if (lo->plh_return_iomode == 0)
                lo->plh_return_iomode = range.iomode;
        else if (lo->plh_return_iomode != range.iomode)
@@ -2207,13 +2221,12 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        if (ld->prepare_layoutcommit) {
                status = ld->prepare_layoutcommit(&data->args);
                if (status) {
+                       put_rpccred(data->cred);
                        spin_lock(&inode->i_lock);
                        set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
                        if (end_pos > nfsi->layout->plh_lwb)
                                nfsi->layout->plh_lwb = end_pos;
-                       spin_unlock(&inode->i_lock);
-                       put_rpccred(data->cred);
-                       goto clear_layoutcommitting;
+                       goto out_unlock;
                }
        }
 
index 65869ca9c851dbf4f0b289ca84865a018c2b6e57..75a35a1afa7944d4ac54bd94994cddf1fd05ab54 100644 (file)
@@ -1379,24 +1379,27 @@ static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
 {
        struct nfs_pgio_args *argp = &hdr->args;
        struct nfs_pgio_res *resp = &hdr->res;
+       u64 size = argp->offset + resp->count;
 
        if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
+               fattr->size = size;
+       if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode)) {
+               fattr->valid &= ~NFS_ATTR_FATTR_SIZE;
                return;
-       if (argp->offset + resp->count != fattr->size)
-               return;
-       if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode))
+       }
+       if (size != fattr->size)
                return;
        /* Set attribute barrier */
        nfs_fattr_set_barrier(fattr);
+       /* ...and update size */
+       fattr->valid |= NFS_ATTR_FATTR_SIZE;
 }
 
 void nfs_writeback_update_inode(struct nfs_pgio_header *hdr)
 {
-       struct nfs_fattr *fattr = hdr->res.fattr;
+       struct nfs_fattr *fattr = &hdr->fattr;
        struct inode *inode = hdr->inode;
 
-       if (fattr == NULL)
-               return;
        spin_lock(&inode->i_lock);
        nfs_writeback_check_extend(hdr, fattr);
        nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
index 6904213a436368e47628af85701a3beb68e0550b..ebf90e487c752b59270aa559588a8805468ad0f5 100644 (file)
@@ -212,6 +212,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
        BUG_ON(!ls->ls_file);
 
        if (nfsd4_layout_setlease(ls)) {
+               fput(ls->ls_file);
                put_nfs4_file(fp);
                kmem_cache_free(nfs4_layout_stateid_cache, ls);
                return NULL;
index 61dfb33f05593c1b19dff8a5346dee37a3539d79..95202719a1fd26bd27ea71a2fe85ec1c248e8d13 100644 (file)
@@ -4396,9 +4396,9 @@ laundromat_main(struct work_struct *laundry)
        queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
 }
 
-static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
+static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
 {
-       if (!fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle))
+       if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle))
                return nfserr_bad_stateid;
        return nfs_ok;
 }
@@ -4601,9 +4601,6 @@ nfs4_check_olstateid(struct svc_fh *fhp, struct nfs4_ol_stateid *ols, int flags)
 {
        __be32 status;
 
-       status = nfs4_check_fh(fhp, ols);
-       if (status)
-               return status;
        status = nfsd4_check_openowner_confirmed(ols);
        if (status)
                return status;
@@ -4690,6 +4687,9 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
                status = nfserr_bad_stateid;
                break;
        }
+       if (status)
+               goto out;
+       status = nfs4_check_fh(fhp, s);
 
 done:
        if (!status && filpp)
@@ -4798,7 +4798,7 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
        status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
        if (status)
                return status;
-       return nfs4_check_fh(current_fh, stp);
+       return nfs4_check_fh(current_fh, &stp->st_stid);
 }
 
 /* 
index 54633858733a8da5ac978fe1d19a0a055488e01d..75e0563c09d1911d927501ee52b53a3bd988940e 100644 (file)
@@ -2143,6 +2143,7 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
                              FATTR4_WORD0_RDATTR_ERROR)
 #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+#define WORD2_ABSENT_FS_ATTRS 0
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 static inline __be32
@@ -2171,7 +2172,7 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
 { return 0; }
 #endif
 
-static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
 {
        /* As per referral draft:  */
        if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
@@ -2184,6 +2185,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
        }
        *bmval0 &= WORD0_ABSENT_FS_ATTRS;
        *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+       *bmval2 &= WORD2_ABSENT_FS_ATTRS;
        return 0;
 }
 
@@ -2246,8 +2248,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
 
        if (exp->ex_fslocs.migrated) {
-               BUG_ON(bmval[2]);
-               status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+               status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
                if (status)
                        goto out;
        }
@@ -2286,8 +2287,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
        }
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
-       if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
-                       bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+       if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
+            bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
                err = security_inode_getsecctx(d_inode(dentry),
                                                &context, &contextlen);
                contextsupport = (err == 0);
index 9a20e513d7eb89ee21228e6af0a723996c4150a5..aba43811d6ef1221c68b275afda0174f072343bf 100644 (file)
@@ -1369,7 +1369,6 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        case NILFS_IOCTL_SYNC:
        case NILFS_IOCTL_RESIZE:
        case NILFS_IOCTL_SET_ALLOC_RANGE:
-       case FITRIM:
                break;
        default:
                return -ENOIOCTLCMD;
index 92e48c70f0f05542a75804fe7aac752672abd214..39ddcaf0918f145fb3f2cb916d27aa1b866a220e 100644 (file)
@@ -412,16 +412,36 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
                                         unsigned int flags)
 {
        struct fsnotify_mark *lmark, *mark;
+       LIST_HEAD(to_free);
 
+       /*
+        * We have to be really careful here. Anytime we drop mark_mutex, e.g.
+        * fsnotify_clear_marks_by_inode() can come and free marks. Even in our
+        * to_free list so we have to use mark_mutex even when accessing that
+        * list. And freeing mark requires us to drop mark_mutex. So we can
+        * reliably free only the first mark in the list. That's why we first
+        * move marks to free to to_free list in one go and then free marks in
+        * to_free list one by one.
+        */
        mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
        list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
-               if (mark->flags & flags) {
-                       fsnotify_get_mark(mark);
-                       fsnotify_destroy_mark_locked(mark, group);
-                       fsnotify_put_mark(mark);
-               }
+               if (mark->flags & flags)
+                       list_move(&mark->g_list, &to_free);
        }
        mutex_unlock(&group->mark_mutex);
+
+       while (1) {
+               mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+               if (list_empty(&to_free)) {
+                       mutex_unlock(&group->mark_mutex);
+                       break;
+               }
+               mark = list_first_entry(&to_free, struct fsnotify_mark, g_list);
+               fsnotify_get_mark(mark);
+               fsnotify_destroy_mark_locked(mark, group);
+               mutex_unlock(&group->mark_mutex);
+               fsnotify_put_mark(mark);
+       }
 }
 
 /*
index 1a35c6139656344516aacd59c7120f6fb877f2a2..0f5fd9db8194ef5d135f1896f6e2645a5f059cd8 100644 (file)
@@ -685,7 +685,7 @@ static int ocfs2_direct_IO_zero_extend(struct ocfs2_super *osb,
 
        if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
                u64 s = i_size_read(inode);
-               sector_t sector = (p_cpos << (osb->s_clustersize_bits - 9)) +
+               sector_t sector = ((u64)p_cpos << (osb->s_clustersize_bits - 9)) +
                        (do_div(s, osb->s_clustersize) >> 9);
 
                ret = blkdev_issue_zeroout(osb->sb->s_bdev, sector,
@@ -910,7 +910,7 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb,
                BUG_ON(!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN));
 
                ret = blkdev_issue_zeroout(osb->sb->s_bdev,
-                               p_cpos << (osb->s_clustersize_bits - 9),
+                               (u64)p_cpos << (osb->s_clustersize_bits - 9),
                                zero_len_head >> 9, GFP_NOFS, false);
                if (ret < 0)
                        mlog_errno(ret);
index 8b23aa2f52ddafe31be83b730d7219693222a1c5..23157e40dd740204bc10f9eaeb55ec08f2f0dfb4 100644 (file)
@@ -4025,9 +4025,13 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
        osb->dc_work_sequence = osb->dc_wake_sequence;
 
        processed = osb->blocked_lock_count;
-       while (processed) {
-               BUG_ON(list_empty(&osb->blocked_lock_list));
-
+       /*
+        * blocked lock processing in this loop might call iput which can
+        * remove items off osb->blocked_lock_list. Downconvert up to
+        * 'processed' number of locks, but stop short if we had some
+        * removed in ocfs2_mark_lockres_freeing when downconverting.
+        */
+       while (processed && !list_empty(&osb->blocked_lock_list)) {
                lockres = list_entry(osb->blocked_lock_list.next,
                                     struct ocfs2_lock_res, l_blocked_list);
                list_del_init(&lockres->l_blocked_list);
index 53e6c40ed4c6a451bc38d0727176c0827e564930..3cb097ccce607a8c0e6ebb1679a80542182f58b5 100644 (file)
@@ -980,7 +980,6 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case OCFS2_IOC_GROUP_EXTEND:
        case OCFS2_IOC_GROUP_ADD:
        case OCFS2_IOC_GROUP_ADD64:
-       case FITRIM:
                break;
        case OCFS2_IOC_REFLINK:
                if (copy_from_user(&args, argp, sizeof(args)))
index f140e3dbfb7bdeb967cad4639c9e32c236a3cced..d9da5a4e93821ddbee9f2fb449666c207417e523 100644 (file)
@@ -343,6 +343,9 @@ struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
        struct path realpath;
        enum ovl_path_type type;
 
+       if (d_is_dir(dentry))
+               return d_backing_inode(dentry);
+
        type = ovl_path_real(dentry, &realpath);
        if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
                err = ovl_want_write(dentry);
index 7114ce6e6b9ef038f415550b925ac50a95be978c..0fcdbe7ca6480e7950092cfd0dc7d0ce431ef548 100644 (file)
@@ -20,8 +20,6 @@
 #define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
 #define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
 #define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED)
-#define IS_MNT_LOCKED_AND_LAZY(m) \
-       (((m)->mnt.mnt_flags & (MNT_LOCKED|MNT_SYNC_UMOUNT)) == MNT_LOCKED)
 
 #define CL_EXPIRE              0x01
 #define CL_SLAVE               0x02
index d751fcb637bb73d756b7da9c4b0aa337d53647b2..1ade1206bb896f50ad326d281c42ec56e66d8372 100644 (file)
@@ -75,3 +75,9 @@ config PROC_PAGE_MONITOR
 config PROC_CHILDREN
        bool "Include /proc/<pid>/task/<tid>/children file"
        default n
+       help
+         Provides a fast way to retrieve first level children pids of a task. See
+         <file:Documentation/filesystems/proc.txt> for more information.
+
+         Say Y if you are running any user-space software which takes benefit from
+         this interface. For example, rkt is such a piece of software.
index 87782e874b6af4523adff3e7e721046d5f857ee0..aa50d1ac28fc6189a9489d1b679fcf86115e633c 100644 (file)
@@ -243,6 +243,11 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
        len1 = arg_end - arg_start;
        len2 = env_end - env_start;
 
+       /* Empty ARGV. */
+       if (len1 == 0) {
+               rv = 0;
+               goto out_free_page;
+       }
        /*
         * Inherently racy -- command line shares address space
         * with code and data.
index 91a4e6426321885eaa226081be2c39ad35a95f74..92e6726f6e3732573bd9a64f3b313cc3508ce519 100644 (file)
@@ -92,7 +92,7 @@ static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
                             roundup(sizeof(CORE_STR), 4)) +
                        roundup(sizeof(struct elf_prstatus), 4) +
                        roundup(sizeof(struct elf_prpsinfo), 4) +
-                       roundup(sizeof(struct task_struct), 4);
+                       roundup(arch_task_struct_size, 4);
        *elf_buflen = PAGE_ALIGN(*elf_buflen);
        return size + *elf_buflen;
 }
@@ -415,7 +415,7 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
        /* set up the task structure */
        notes[2].name   = CORE_STR;
        notes[2].type   = NT_TASKSTRUCT;
-       notes[2].datasz = sizeof(struct task_struct);
+       notes[2].datasz = arch_task_struct_size;
        notes[2].data   = current;
 
        nhdr->p_filesz  += notesize(&notes[2]);
index 7e412ad748363489baad12cbb644b8074d78cfeb..270221fcef42cc42fcfdbc098b587b571be65a12 100644 (file)
@@ -121,8 +121,9 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
-               if (kinfo->si_code == BUS_MCEERR_AR ||
-                   kinfo->si_code == BUS_MCEERR_AO)
+               if (kinfo->si_signo == SIGBUS &&
+                   (kinfo->si_code == BUS_MCEERR_AR ||
+                    kinfo->si_code == BUS_MCEERR_AO))
                        err |= __put_user((short) kinfo->si_addr_lsb,
                                          &uinfo->ssi_addr_lsb);
 #endif
index 6afac3d561ac81f6f5861f86a0dc4eb2a7d1fca2..8d0b3ade0ff0ef8a65f8714330a3bfd49201c0d8 100644 (file)
@@ -1652,17 +1652,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                       iinfo->i_ext.i_data, inode->i_sb->s_blocksize -
                                        sizeof(struct unallocSpaceEntry));
                use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE);
-               use->descTag.tagLocation =
-                               cpu_to_le32(iinfo->i_location.logicalBlockNum);
-               crclen = sizeof(struct unallocSpaceEntry) +
-                               iinfo->i_lenAlloc - sizeof(struct tag);
-               use->descTag.descCRCLength = cpu_to_le16(crclen);
-               use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use +
-                                                          sizeof(struct tag),
-                                                          crclen));
-               use->descTag.tagChecksum = udf_tag_checksum(&use->descTag);
+               crclen = sizeof(struct unallocSpaceEntry);
 
-               goto out;
+               goto finish;
        }
 
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
@@ -1782,6 +1774,8 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
                crclen = sizeof(struct extendedFileEntry);
        }
+
+finish:
        if (iinfo->i_strat4096) {
                fe->icbTag.strategyType = cpu_to_le16(4096);
                fe->icbTag.strategyParameter = cpu_to_le16(1);
@@ -1791,7 +1785,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                fe->icbTag.numEntries = cpu_to_le16(1);
        }
 
-       if (S_ISDIR(inode->i_mode))
+       if (iinfo->i_use)
+               fe->icbTag.fileType = ICBTAG_FILE_TYPE_USE;
+       else if (S_ISDIR(inode->i_mode))
                fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY;
        else if (S_ISREG(inode->i_mode))
                fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR;
@@ -1828,7 +1824,6 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                                                  crclen));
        fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag);
 
-out:
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
 
index 20de88d1bf86205d126d5e27b43298af9b836a79..dd714037c322d0009d8df40e73bf5adf3aa892d4 100644 (file)
@@ -159,11 +159,10 @@ xfs_attr3_rmt_write_verify(
        struct xfs_buf  *bp)
 {
        struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       int             blksize = mp->m_attr_geo->blksize;
        char            *ptr;
        int             len;
        xfs_daddr_t     bno;
-       int             blksize = mp->m_attr_geo->blksize;
 
        /* no verification of non-crc buffers */
        if (!xfs_sb_version_hascrc(&mp->m_sb))
@@ -175,16 +174,22 @@ xfs_attr3_rmt_write_verify(
        ASSERT(len >= blksize);
 
        while (len > 0) {
+               struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
+
                if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
                        xfs_buf_ioerror(bp, -EFSCORRUPTED);
                        xfs_verifier_error(bp);
                        return;
                }
-               if (bip) {
-                       struct xfs_attr3_rmt_hdr *rmt;
 
-                       rmt = (struct xfs_attr3_rmt_hdr *)ptr;
-                       rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+               /*
+                * Ensure we aren't writing bogus LSNs to disk. See
+                * xfs_attr3_rmt_hdr_set() for the explanation.
+                */
+               if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
+                       xfs_buf_ioerror(bp, -EFSCORRUPTED);
+                       xfs_verifier_error(bp);
+                       return;
                }
                xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
 
@@ -221,6 +226,18 @@ xfs_attr3_rmt_hdr_set(
        rmt->rm_owner = cpu_to_be64(ino);
        rmt->rm_blkno = cpu_to_be64(bno);
 
+       /*
+        * Remote attribute blocks are written synchronously, so we don't
+        * have an LSN that we can stamp in them that makes any sense to log
+        * recovery. To ensure that log recovery handles overwrites of these
+        * blocks sanely (i.e. once they've been freed and reallocated as some
+        * other type of metadata) we need to ensure that the LSN has a value
+        * that tells log recovery to ignore the LSN and overwrite the buffer
+        * with whatever is in it's log. To do this, we use the magic
+        * NULLCOMMITLSN to indicate that the LSN is invalid.
+        */
+       rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
+
        return sizeof(struct xfs_attr3_rmt_hdr);
 }
 
@@ -434,14 +451,21 @@ xfs_attr_rmtval_set(
 
                /*
                 * Allocate a single extent, up to the size of the value.
+                *
+                * Note that we have to consider this a data allocation as we
+                * write the remote attribute without logging the contents.
+                * Hence we must ensure that we aren't using blocks that are on
+                * the busy list so that we don't overwrite blocks which have
+                * recently been freed but their transactions are not yet
+                * committed to disk. If we overwrite the contents of a busy
+                * extent and then crash then the block may not contain the
+                * correct metadata after log recovery occurs.
                 */
                xfs_bmap_init(args->flist, args->firstblock);
                nmap = 1;
                error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
-                                 blkcnt,
-                                 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 args->firstblock, args->total, &map, &nmap,
-                                 args->flist);
+                                 blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
+                                 args->total, &map, &nmap, args->flist);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                &committed);
index f0e8249722d40a0dcaf9f31bc25effaba142b0a9..db4acc1c3e73479cdf32322944a7fa1bcf34b96f 100644 (file)
@@ -1514,18 +1514,27 @@ xfs_filemap_fault(
        struct vm_area_struct   *vma,
        struct vm_fault         *vmf)
 {
-       struct xfs_inode        *ip = XFS_I(file_inode(vma->vm_file));
+       struct inode            *inode = file_inode(vma->vm_file);
        int                     ret;
 
-       trace_xfs_filemap_fault(ip);
+       trace_xfs_filemap_fault(XFS_I(inode));
 
        /* DAX can shortcut the normal fault path on write faults! */
-       if ((vmf->flags & FAULT_FLAG_WRITE) && IS_DAX(VFS_I(ip)))
+       if ((vmf->flags & FAULT_FLAG_WRITE) && IS_DAX(inode))
                return xfs_filemap_page_mkwrite(vma, vmf);
 
-       xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
-       ret = filemap_fault(vma, vmf);
-       xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
+       xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
+       if (IS_DAX(inode)) {
+               /*
+                * we do not want to trigger unwritten extent conversion on read
+                * faults - that is unnecessary overhead and would also require
+                * changes to xfs_get_blocks_direct() to map unwritten extent
+                * ioend for conversion on read-only mappings.
+                */
+               ret = __dax_fault(vma, vmf, xfs_get_blocks_direct, NULL);
+       } else
+               ret = filemap_fault(vma, vmf);
+       xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
 
        return ret;
 }
index 01dd228ca05e315b88feb7afbfaf3e81d728878b..480ebba8464f38dbb0608b579185ad93a0600913 100644 (file)
@@ -1886,9 +1886,14 @@ xlog_recover_get_buf_lsn(
                uuid = &((struct xfs_dir3_blk_hdr *)blk)->uuid;
                break;
        case XFS_ATTR3_RMT_MAGIC:
-               lsn = be64_to_cpu(((struct xfs_attr3_rmt_hdr *)blk)->rm_lsn);
-               uuid = &((struct xfs_attr3_rmt_hdr *)blk)->rm_uuid;
-               break;
+               /*
+                * Remote attr blocks are written synchronously, rather than
+                * being logged. That means they do not contain a valid LSN
+                * (i.e. transactionally ordered) in them, and hence any time we
+                * see a buffer to replay over the top of a remote attribute
+                * block we should simply do so.
+                */
+               goto recover_immediately;
        case XFS_SB_MAGIC:
                lsn = be64_to_cpu(((struct xfs_dsb *)blk)->sb_lsn);
                uuid = &((struct xfs_dsb *)blk)->sb_uuid;
diff --git a/include/asm-generic/mm-arch-hooks.h b/include/asm-generic/mm-arch-hooks.h
new file mode 100644 (file)
index 0000000..5ff0e51
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Architecture specific mm hooks
+ */
+
+#ifndef _ASM_GENERIC_MM_ARCH_HOOKS_H
+#define _ASM_GENERIC_MM_ARCH_HOOKS_H
+
+/*
+ * This file should be included through arch/../include/asm/Kbuild for
+ * the architecture which doesn't need specific mm hooks.
+ *
+ * In that case, the generic hooks defined in include/linux/mm-arch-hooks.h
+ * are used.
+ */
+
+#endif /* _ASM_GENERIC_MM_ARCH_HOOKS_H */
index 48db6a56975f5ebc874d19054828b70a5f4aaa15..5aa519711e0b6fcb1212a517e50be5afac8ed7d7 100644 (file)
@@ -691,7 +691,7 @@ struct drm_vblank_crtc {
        struct timer_list disable_timer;                /* delayed disable timer */
 
        /* vblank counter, protected by dev->vblank_time_lock for writes */
-       unsigned long count;
+       u32 count;
        /* vblank timestamps, protected by dev->vblank_time_lock for writes */
        struct timeval time[DRM_VBLANKTIME_RBSIZE];
 
index 57ca8cc383a615344498202384b1b814911bc766..3b4d8a4a23fb760867fc7d59ede2a3459eac2375 100644 (file)
@@ -743,8 +743,6 @@ struct drm_connector {
        uint8_t num_h_tile, num_v_tile;
        uint8_t tile_h_loc, tile_v_loc;
        uint16_t tile_h_size, tile_v_size;
-
-       struct list_head destroy_list;
 };
 
 /**
index c8fc187061de5fbd9fc8545f602a62baaa45b8cc..918aa68b5199d54501a2a9d68404e44388e9e04e 100644 (file)
@@ -168,6 +168,7 @@ struct drm_encoder_helper_funcs {
  * @get_modes: get mode list for this connector
  * @mode_valid: is this mode valid on the given connector? (optional)
  * @best_encoder: return the preferred encoder for this connector
+ * @atomic_best_encoder: atomic version of @best_encoder
  *
  * The helper operations are called by the mid-layer CRTC helper.
  */
@@ -176,6 +177,8 @@ struct drm_connector_helper_funcs {
        enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
                                           struct drm_display_mode *mode);
        struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
+       struct drm_encoder *(*atomic_best_encoder)(struct drm_connector *connector,
+                                                  struct drm_connector_state *connector_state);
 };
 
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
index 799050198323e852c7cbb45e3c1236cc67d386ac..53c53c459b15c8207997da61234d0ab9ea2805ae 100644 (file)
@@ -347,6 +347,25 @@ static inline int drm_eld_mnl(const uint8_t *eld)
        return (eld[DRM_ELD_CEA_EDID_VER_MNL] & DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
 }
 
+/**
+ * drm_eld_sad - Get ELD SAD structures.
+ * @eld: pointer to an eld memory structure with sad_count set
+ */
+static inline const uint8_t *drm_eld_sad(const uint8_t *eld)
+{
+       unsigned int ver, mnl;
+
+       ver = (eld[DRM_ELD_VER] & DRM_ELD_VER_MASK) >> DRM_ELD_VER_SHIFT;
+       if (ver != 2 && ver != 31)
+               return NULL;
+
+       mnl = drm_eld_mnl(eld);
+       if (mnl > 16)
+               return NULL;
+
+       return eld + DRM_ELD_CEA_SAD(mnl, 0);
+}
+
 /**
  * drm_eld_sad_count - Get ELD SAD count.
  * @eld: pointer to an eld memory structure with sad_count set
index 45c39a37f9249562761dc9615ffecf12ec194846..8bc073d297db2a233cf389d6c0656dec78c0445a 100644 (file)
        {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6617, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index c471dfc93b716e162815709a25e5a705c4b45159..d2445fa9999f9638d99861c1b03b4d0ca3e47c57 100644 (file)
@@ -58,6 +58,19 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
        acpi_fwnode_handle(adev) : NULL)
 #define ACPI_HANDLE(dev)               acpi_device_handle(ACPI_COMPANION(dev))
 
+/**
+ * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with
+ * the PCI-defined class-code information
+ *
+ * @_cls : the class, subclass, prog-if triple for this device
+ * @_msk : the class mask for this device
+ *
+ * This macro is used to create a struct acpi_device_id that matches a
+ * specific PCI class. The .id and .driver_data fields will be left
+ * initialized with the default value.
+ */
+#define ACPI_DEVICE_CLASS(_cls, _msk)  .cls = (_cls), .cls_msk = (_msk),
+
 static inline bool has_acpi_companion(struct device *dev)
 {
        return is_acpi_node(dev->fwnode);
@@ -309,9 +322,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
 
 int acpi_resources_are_enforced(void);
 
-int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
-                       unsigned long flags, char *desc);
-
 #ifdef CONFIG_HIBERNATION
 void __init acpi_no_s4_hw_signature(void);
 #endif
@@ -446,6 +456,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *);
 #define ACPI_COMPANION(dev)            (NULL)
 #define ACPI_COMPANION_SET(dev, adev)  do { } while (0)
 #define ACPI_HANDLE(dev)               (NULL)
+#define ACPI_DEVICE_CLASS(_cls, _msk)  .cls = (0), .cls_msk = (0),
 
 struct fwnode_handle;
 
@@ -507,13 +518,6 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n,
        return 0;
 }
 
-static inline int acpi_reserve_region(u64 start, unsigned int length,
-                                     u8 space_id, unsigned long flags,
-                                     char *desc)
-{
-       return -ENXIO;
-}
-
 struct acpi_table_header;
 static inline int acpi_table_parse(char *id,
                                int (*handler)(struct acpi_table_header *))
index c7df89f99115c82bdd8f5accc7199bd6034d5e6f..58fe9e8b6fd7f305f46beeda817a66f0fb8ffccb 100644 (file)
@@ -2,7 +2,7 @@
  * ARM PrimeXsys System Controller SP810 header file
  *
  * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index fed36418dd1c2fe8c1c084278080f2ff23169725..d2992bfa17063a052a08a106b9105284ce4bfa4a 100644 (file)
@@ -45,6 +45,7 @@ enum {
        ATA_SECT_SIZE           = 512,
        ATA_MAX_SECTORS_128     = 128,
        ATA_MAX_SECTORS         = 256,
+       ATA_MAX_SECTORS_1024    = 1024,
        ATA_MAX_SECTORS_LBA48   = 65535,/* TODO: 65536? */
        ATA_MAX_SECTORS_TAPE    = 65535,
 
@@ -384,8 +385,6 @@ enum {
        SATA_SSP                = 0x06, /* Software Settings Preservation */
        SATA_DEVSLP             = 0x09, /* Device Sleep */
 
-       SETFEATURE_SENSE_DATA = 0xC3, /* Sense Data Reporting feature */
-
        /* feature values for SET_MAX */
        ATA_SET_MAX_ADDR        = 0x00,
        ATA_SET_MAX_PASSWD      = 0x01,
@@ -529,8 +528,6 @@ struct ata_bmdma_prd {
 #define ata_id_cdb_intr(id)    (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
 #define ata_id_has_da(id)      ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
 #define ata_id_has_devslp(id)  ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
-#define ata_id_has_ncq_autosense(id) \
-                               ((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))
 
 static inline bool ata_id_has_hipm(const u16 *id)
 {
@@ -719,20 +716,6 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
        return false;
 }
 
-static inline bool ata_id_has_sense_reporting(const u16 *id)
-{
-       if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
-               return false;
-       return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
-}
-
-static inline bool ata_id_sense_reporting_enabled(const u16 *id)
-{
-       if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
-               return false;
-       return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
-}
-
 /**
  *     ata_id_major_version    -       get ATA level of drive
  *     @id: Identify data
index 58cfab80dd707ff28d8b4e12fdf735bc24f7f60b..1b62d768c7df5ea3053d09ed3878d1d7a16837b2 100644 (file)
@@ -47,6 +47,7 @@ struct blkcg {
 
        struct blkcg_policy_data        *pd[BLKCG_MAX_POLS];
 
+       struct list_head                all_blkcgs_node;
 #ifdef CONFIG_CGROUP_WRITEBACK
        struct list_head                cgwb_list;
 #endif
@@ -88,18 +89,12 @@ struct blkg_policy_data {
  * Policies that need to keep per-blkcg data which is independent
  * from any request_queue associated to it must specify its size
  * with the cpd_size field of the blkcg_policy structure and
- * embed a blkcg_policy_data in it. blkcg core allocates
- * policy-specific per-blkcg structures lazily the first time
- * they are actually needed, so it handles them together with
- * blkgs. cpd_init() is invoked to let each policy handle
- * per-blkcg data.
+ * embed a blkcg_policy_data in it.  cpd_init() is invoked to let
+ * each policy handle per-blkcg data.
  */
 struct blkcg_policy_data {
        /* the policy id this per-policy data belongs to */
        int                             plid;
-
-       /* used during policy activation */
-       struct list_head                alloc_node;
 };
 
 /* association between a blk cgroup and a request queue */
index 73b45225a7ca1bbe749ea3b62e38a35add22936b..e6797ded700ec8f7ef6a8fccccddf71212715077 100644 (file)
@@ -317,6 +317,13 @@ sb_getblk(struct super_block *sb, sector_t block)
        return __getblk_gfp(sb->s_bdev, block, sb->s_blocksize, __GFP_MOVABLE);
 }
 
+
+static inline struct buffer_head *
+sb_getblk_gfp(struct super_block *sb, sector_t block, gfp_t gfp)
+{
+       return __getblk_gfp(sb->s_bdev, block, sb->s_blocksize, gfp);
+}
+
 static inline struct buffer_head *
 sb_find_get_block(struct super_block *sb, sector_t block)
 {
index b6a52a4b457aaaff2db3f55e2fd3bb78d07a6ab1..51bb6532785c3b9918698c3761d5a6e5088e176c 100644 (file)
 /**
  * struct can_skb_priv - private additional data inside CAN sk_buffs
  * @ifindex:   ifindex of the first interface the CAN frame appeared on
+ * @skbcnt:    atomic counter to have an unique id together with skb pointer
  * @cf:                align to the following CAN frame at skb->data
  */
 struct can_skb_priv {
        int ifindex;
+       int skbcnt;
        struct can_frame cf[0];
 };
 
index e15499422fdcc7686942ce88389d686d9078cd79..37753278987ac654a5e00797e6d6b81e4b2353c0 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/radix-tree.h>
 #include <linux/uio.h>
 #include <linux/workqueue.h>
+#include <net/net_namespace.h>
 
 #include <linux/ceph/types.h>
 #include <linux/ceph/buffer.h>
@@ -56,6 +57,7 @@ struct ceph_messenger {
        struct ceph_entity_addr my_enc_addr;
 
        atomic_t stopping;
+       possible_net_t net;
        bool nocrc;
        bool tcp_nodelay;
 
@@ -267,6 +269,7 @@ extern void ceph_messenger_init(struct ceph_messenger *msgr,
                        u64 required_features,
                        bool nocrc,
                        bool tcp_nodelay);
+extern void ceph_messenger_fini(struct ceph_messenger *msgr);
 
 extern void ceph_con_init(struct ceph_connection *con, void *private,
                        const struct ceph_connection_operations *ops,
index a240b18e86fa4e6cfcc1aaea2b00d4d899c44bdf..08bffcc466de7e5bce4359b3174ba8105e734a35 100644 (file)
@@ -33,18 +33,19 @@ struct clk_lookup {
        }
 
 struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
-       const char *dev_fmt, ...);
+       const char *dev_fmt, ...) __printf(3, 4);
 
 void clkdev_add(struct clk_lookup *cl);
 void clkdev_drop(struct clk_lookup *cl);
 
 struct clk_lookup *clkdev_create(struct clk *clk, const char *con_id,
-       const char *dev_fmt, ...);
+       const char *dev_fmt, ...) __printf(3, 4);
 
 void clkdev_add_table(struct clk_lookup *, size_t);
 int clk_add_alias(const char *, const char *, const char *, struct device *);
 
-int clk_register_clkdev(struct clk *, const char *, const char *, ...);
+int clk_register_clkdev(struct clk *, const char *, const char *, ...)
+       __printf(3, 4);
 int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t);
 
 #ifdef CONFIG_COMMON_CLK
index ab25814690bc649421cc16092653ae5217406198..a76c9172b2eb08de11a33331c35c7533ed041967 100644 (file)
@@ -424,7 +424,7 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
 
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
 
-extern int compat_printk(const char *fmt, ...);
+extern __printf(1, 2) int compat_printk(const char *fmt, ...);
 extern void sigset_from_compat(sigset_t *set, const compat_sigset_t *compat);
 extern void sigset_to_compat(compat_sigset_t *compat, const sigset_t *set);
 
index 7f8ad9593da725438aaefb397b99d9fea4109f90..e08a6ae7c0a422fa72fe0b05d47faf14e651e5fb 100644 (file)
 # define __release(x)  __context__(x,-1)
 # define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
 # define __percpu      __attribute__((noderef, address_space(3)))
+# define __pmem                __attribute__((noderef, address_space(5)))
 #ifdef CONFIG_SPARSE_RCU_POINTER
 # define __rcu         __attribute__((noderef, address_space(4)))
 #else
 # define __rcu
-# define __pmem                __attribute__((noderef, address_space(5)))
 #endif
 extern void __chk_user_ptr(const volatile void __user *);
 extern void __chk_io_ptr(const volatile void __iomem *);
index c9e5c57e4edf2c09ccc4c09c72c54a87c1ecbd9c..63a36e89d0eb6b3f718d7058b723291662c186d3 100644 (file)
@@ -64,7 +64,8 @@ struct config_item {
        struct dentry           *ci_dentry;
 };
 
-extern int config_item_set_name(struct config_item *, const char *, ...);
+extern __printf(2, 3)
+int config_item_set_name(struct config_item *, const char *, ...);
 
 static inline char *config_item_name(struct config_item * item)
 {
index 76abba4b238ece14f8a2bd9bcce5ab53306c61fd..dcacb1a72e26d0755703135016105ae511a2b042 100644 (file)
@@ -340,7 +340,27 @@ struct cper_ia_proc_ctx {
        __u64   mm_reg_addr;
 };
 
-/* Memory Error Section */
+/* Old Memory Error Section UEFI 2.1, 2.2 */
+struct cper_sec_mem_err_old {
+       __u64   validation_bits;
+       __u64   error_status;
+       __u64   physical_addr;
+       __u64   physical_addr_mask;
+       __u16   node;
+       __u16   card;
+       __u16   module;
+       __u16   bank;
+       __u16   device;
+       __u16   row;
+       __u16   column;
+       __u16   bit_pos;
+       __u64   requestor_id;
+       __u64   responder_id;
+       __u64   target_id;
+       __u8    error_type;
+};
+
+/* Memory Error Section UEFI >= 2.3 */
 struct cper_sec_mem_err {
        __u64   validation_bits;
        __u64   error_status;
index c0fb6b1b4712c30bdf9f7749fefead8a5a2be622..23c30bdcca8631f80242d62d4b167d20e2814c75 100644 (file)
@@ -40,9 +40,10 @@ extern void cpu_remove_dev_attr(struct device_attribute *attr);
 extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
 extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
 
-extern struct device *cpu_device_create(struct device *parent, void *drvdata,
-                                       const struct attribute_group **groups,
-                                       const char *fmt, ...);
+extern __printf(4, 5)
+struct device *cpu_device_create(struct device *parent, void *drvdata,
+                                const struct attribute_group **groups,
+                                const char *fmt, ...);
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
 extern ssize_t arch_cpu_probe(const char *, size_t);
index 29ad97c34fd5cf4bcdeec373d2ad5691bb2ec6c3..bde1e567b3a93ad5feb7a0d2aa980a07e28270d5 100644 (file)
@@ -62,6 +62,7 @@ struct cpufreq_policy {
        /* CPUs sharing clock, require sw coordination */
        cpumask_var_t           cpus;   /* Online CPUs only */
        cpumask_var_t           related_cpus; /* Online + Offline CPUs */
+       cpumask_var_t           real_cpus; /* Related and present */
 
        unsigned int            shared_type; /* ACPI: ANY or ALL affected CPUs
                                                should set cpufreq */
index d2d50249b7b2a16bd08b3c6f82ea3748836c7afc..d67ae119cf4eb9d3143d5019108f1d7fbf252b88 100644 (file)
@@ -327,7 +327,8 @@ static inline unsigned d_count(const struct dentry *dentry)
 /*
  * helper function for dentry_operations.d_dname() members
  */
-extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
+extern __printf(4, 5)
+char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 extern char *simple_dname(struct dentry *, char *, int);
 
 extern char *__d_path(const struct path *, const struct path *, char *, int);
index 5a31bf3a40243e1faff078fdc509361568143f01..a2b4ea70a9467520d93a556190ca8995183e4af9 100644 (file)
@@ -637,8 +637,9 @@ extern int devres_release_group(struct device *dev, void *id);
 
 /* managed devm_k.alloc/kfree for device drivers */
 extern void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp);
-extern char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt,
-                            va_list ap);
+extern __printf(3, 0)
+char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt,
+                     va_list ap);
 extern __printf(3, 4)
 char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...);
 static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
@@ -1011,12 +1012,10 @@ extern int __must_check device_reprobe(struct device *dev);
 /*
  * Easy functions for dynamically creating devices on the fly
  */
-extern struct device *device_create_vargs(struct class *cls,
-                                         struct device *parent,
-                                         dev_t devt,
-                                         void *drvdata,
-                                         const char *fmt,
-                                         va_list vargs);
+extern __printf(5, 0)
+struct device *device_create_vargs(struct class *cls, struct device *parent,
+                                  dev_t devt, void *drvdata,
+                                  const char *fmt, va_list vargs);
 extern __printf(5, 6)
 struct device *device_create(struct class *cls, struct device *parent,
                             dev_t devt, void *drvdata,
index a0653e560c2679a2eea870035a55cd3282e47894..84b783f277f761a0ef7b940bd1fbab37db60567e 100644 (file)
@@ -55,7 +55,8 @@ struct vm_fault;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
-extern void __init files_init(unsigned long);
+extern void __init files_init(void);
+extern void __init files_maxfiles_init(void);
 
 extern struct files_stat_struct files_stat;
 extern unsigned long get_max_files(void);
@@ -1046,12 +1047,12 @@ extern void locks_remove_file(struct file *);
 extern void locks_release_private(struct file_lock *);
 extern void posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
-extern int posix_lock_file_wait(struct file *, struct file_lock *);
+extern int posix_lock_inode_wait(struct inode *, struct file_lock *);
 extern int posix_unblock_lock(struct file_lock *);
 extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
 extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
-extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
+extern int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
 extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
@@ -1137,7 +1138,8 @@ static inline int posix_lock_file(struct file *filp, struct file_lock *fl,
        return -ENOLCK;
 }
 
-static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
+static inline int posix_lock_inode_wait(struct inode *inode,
+                                       struct file_lock *fl)
 {
        return -ENOLCK;
 }
@@ -1163,8 +1165,8 @@ static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
        return 0;
 }
 
-static inline int flock_lock_file_wait(struct file *filp,
-                                      struct file_lock *request)
+static inline int flock_lock_inode_wait(struct inode *inode,
+                                       struct file_lock *request)
 {
        return -ENOLCK;
 }
@@ -1202,6 +1204,20 @@ static inline void show_fd_locks(struct seq_file *f,
                        struct file *filp, struct files_struct *files) {}
 #endif /* !CONFIG_FILE_LOCKING */
 
+static inline struct inode *file_inode(const struct file *f)
+{
+       return f->f_inode;
+}
+
+static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
+{
+       return posix_lock_inode_wait(file_inode(filp), fl);
+}
+
+static inline int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
+{
+       return flock_lock_inode_wait(file_inode(filp), fl);
+}
 
 struct fasync_struct {
        spinlock_t              fa_lock;
@@ -2011,11 +2027,6 @@ extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
 extern int generic_update_time(struct inode *, struct timespec *, int);
 
-static inline struct inode *file_inode(const struct file *f)
-{
-       return f->f_inode;
-}
-
 /* /sys/fs */
 extern struct kobject *fs_kobj;
 
@@ -2235,7 +2246,7 @@ extern int ioctl_preallocate(struct file *filp, void __user *argp);
 
 /* fs/dcache.c */
 extern void __init vfs_caches_init_early(void);
-extern void __init vfs_caches_init(unsigned long);
+extern void __init vfs_caches_init(void);
 
 extern struct kmem_cache *names_cachep;
 
index 1da602982cf93a6a262bef85967945ffea9c586a..6cd8c0ee4b6f89a9ab93b67515cb6e214e108071 100644 (file)
@@ -116,6 +116,7 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
  *            SAVE_REGS. If another ops with this flag set is already registered
  *            for any of the functions that this ops will be registered for, then
  *            this ops will fail to register or set_filter_ip.
+ * PID     - Is affected by set_ftrace_pid (allows filtering on those pids)
  */
 enum {
        FTRACE_OPS_FL_ENABLED                   = 1 << 0,
@@ -132,6 +133,7 @@ enum {
        FTRACE_OPS_FL_MODIFYING                 = 1 << 11,
        FTRACE_OPS_FL_ALLOC_TRAMP               = 1 << 12,
        FTRACE_OPS_FL_IPMODIFY                  = 1 << 13,
+       FTRACE_OPS_FL_PID                       = 1 << 14,
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -159,6 +161,7 @@ struct ftrace_ops {
        struct ftrace_ops               *next;
        unsigned long                   flags;
        void                            *private;
+       ftrace_func_t                   saved_func;
        int __percpu                    *disabled;
 #ifdef CONFIG_DYNAMIC_FTRACE
        int                             nr_trampolines;
index cc7ec129b329efb9887c0482c5abeb83562b79f7..c8393cd4d44f2d871bdf962c3dad55505e362b32 100644 (file)
@@ -45,7 +45,7 @@ struct seq_file;
  * @base: identifies the first GPIO number handled by this chip;
  *     or, if negative during registration, requests dynamic ID allocation.
  *     DEPRECATION: providing anything non-negative and nailing the base
- *     base offset of GPIO chips is deprecated. Please pass -1 as base to
+ *     offset of GPIO chips is deprecated. Please pass -1 as base to
  *     let gpiolib select the chip base in all possible cases. We want to
  *     get rid of the static GPIO number space in the long run.
  * @ngpio: the number of GPIOs handled by this controller; the last GPIO
index 0042bf330b99ffa6edd77677529753bdd00b79d4..c02b5ce6c5cdb787c3cb5ddb1ca7652dc5fe9d1e 100644 (file)
@@ -230,6 +230,7 @@ struct hid_sensor_common {
        struct platform_device *pdev;
        unsigned usage_id;
        atomic_t data_ready;
+       atomic_t user_requested_state;
        struct iio_trigger *trigger;
        struct hid_sensor_hub_attribute_info poll;
        struct hid_sensor_hub_attribute_info report_state;
index 205026175c4208a8e65423f6042606a5be67bec7..d891f949466ae2b11d2fd063a4493044e5dc9618 100644 (file)
@@ -460,15 +460,14 @@ static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
        return &mm->page_table_lock;
 }
 
-static inline bool hugepages_supported(void)
-{
-       /*
-        * Some platform decide whether they support huge pages at boot
-        * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
-        * there is no such support
-        */
-       return HPAGE_SHIFT != 0;
-}
+#ifndef hugepages_supported
+/*
+ * Some platform decide whether they support huge pages at boot
+ * time. Some of them, such as powerpc, set HPAGE_SHIFT to 0
+ * when there is no such support
+ */
+#define hugepages_supported() (HPAGE_SHIFT != 0)
+#endif
 
 #else  /* CONFIG_HUGETLB_PAGE */
 struct hstate {};
index 7c68c36d3fd88788f043447c5bed889cdd408bb6..b449f378f995ae647077f521d9f7af3af9480a70 100644 (file)
@@ -282,68 +282,8 @@ void __init parse_early_param(void);
 void __init parse_early_options(char *cmdline);
 #endif /* __ASSEMBLY__ */
 
-/**
- * module_init() - driver initialization entry point
- * @x: function to be run at kernel boot time or module insertion
- * 
- * module_init() will either be called during do_initcalls() (if
- * builtin) or at module insertion time (if a module).  There can only
- * be one per module.
- */
-#define module_init(x) __initcall(x);
-
-/**
- * module_exit() - driver exit entry point
- * @x: function to be run when driver is removed
- * 
- * module_exit() will wrap the driver clean-up code
- * with cleanup_module() when used with rmmod when
- * the driver is a module.  If the driver is statically
- * compiled into the kernel, module_exit() has no effect.
- * There can only be one per module.
- */
-#define module_exit(x) __exitcall(x);
-
 #else /* MODULE */
 
-/*
- * In most cases loadable modules do not need custom
- * initcall levels. There are still some valid cases where
- * a driver may be needed early if built in, and does not
- * matter when built as a loadable module. Like bus
- * snooping debug drivers.
- */
-#define early_initcall(fn)             module_init(fn)
-#define core_initcall(fn)              module_init(fn)
-#define core_initcall_sync(fn)         module_init(fn)
-#define postcore_initcall(fn)          module_init(fn)
-#define postcore_initcall_sync(fn)     module_init(fn)
-#define arch_initcall(fn)              module_init(fn)
-#define subsys_initcall(fn)            module_init(fn)
-#define subsys_initcall_sync(fn)       module_init(fn)
-#define fs_initcall(fn)                        module_init(fn)
-#define fs_initcall_sync(fn)           module_init(fn)
-#define rootfs_initcall(fn)            module_init(fn)
-#define device_initcall(fn)            module_init(fn)
-#define device_initcall_sync(fn)       module_init(fn)
-#define late_initcall(fn)              module_init(fn)
-#define late_initcall_sync(fn)         module_init(fn)
-
-#define console_initcall(fn)           module_init(fn)
-#define security_initcall(fn)          module_init(fn)
-
-/* Each module must use one module_init(). */
-#define module_init(initfn)                                    \
-       static inline initcall_t __inittest(void)               \
-       { return initfn; }                                      \
-       int init_module(void) __attribute__((alias(#initfn)));
-
-/* This is only required if you want to be unloadable. */
-#define module_exit(exitfn)                                    \
-       static inline exitcall_t __exittest(void)               \
-       { return exitfn; }                                      \
-       void cleanup_module(void) __attribute__((alias(#exitfn)));
-
 #define __setup_param(str, unique_id, fn)      /* nothing */
 #define __setup(str, func)                     /* nothing */
 #endif
@@ -351,24 +291,6 @@ void __init parse_early_options(char *cmdline);
 /* Data marked not to be saved by software suspend */
 #define __nosavedata __section(.data..nosave)
 
-/* This means "can be init if no module support, otherwise module load
-   may call it." */
-#ifdef CONFIG_MODULES
-#define __init_or_module
-#define __initdata_or_module
-#define __initconst_or_module
-#define __INIT_OR_MODULE       .text
-#define __INITDATA_OR_MODULE   .data
-#define __INITRODATA_OR_MODULE .section ".rodata","a",%progbits
-#else
-#define __init_or_module __init
-#define __initdata_or_module __initdata
-#define __initconst_or_module __initconst
-#define __INIT_OR_MODULE __INIT
-#define __INITDATA_OR_MODULE __INITDATA
-#define __INITRODATA_OR_MODULE __INITRODATA
-#endif /*CONFIG_MODULES*/
-
 #ifdef MODULE
 #define __exit_p(x) x
 #else
index dc767f7c3704639da944153e8bdae7cf40cd804d..f9c1b6d0f2e4bcda9db87aa9d8d5907acd0da2d4 100644 (file)
@@ -258,7 +258,7 @@ extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr,
                                 void *data);
 struct device *iommu_device_create(struct device *parent, void *drvdata,
                                   const struct attribute_group **groups,
-                                  const char *fmt, ...);
+                                  const char *fmt, ...) __printf(4, 5);
 void iommu_device_destroy(struct device *dev);
 int iommu_device_link(struct device *dev, struct device *link);
 void iommu_device_unlink(struct device *dev, struct device *link);
index 92188b0225bb31f33eba9deacc4b9b88036c1d8e..51744bcf74eec7bee678b9e1f63c3a10f247350e 100644 (file)
@@ -484,6 +484,7 @@ extern int irq_chip_set_affinity_parent(struct irq_data *data,
 extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on);
 extern int irq_chip_set_vcpu_affinity_parent(struct irq_data *data,
                                             void *vcpu_info);
+extern int irq_chip_set_type_parent(struct irq_data *data, unsigned int type);
 #endif
 
 /* Handling of unhandled and spurious interrupts: */
index 624a668e61f1a6c5096e2afa78bd403655c11e59..fcea4e48e21f5d7060b2451673abf9a8f47d0001 100644 (file)
@@ -87,7 +87,12 @@ struct irq_desc {
        const char              *name;
 } ____cacheline_internodealigned_in_smp;
 
-#ifndef CONFIG_SPARSE_IRQ
+#ifdef CONFIG_SPARSE_IRQ
+extern void irq_lock_sparse(void);
+extern void irq_unlock_sparse(void);
+#else
+static inline void irq_lock_sparse(void) { }
+static inline void irq_unlock_sparse(void) { }
 extern struct irq_desc irq_desc[NR_IRQS];
 #endif
 
index 5f0be58640ea6e73f88dd02cb3ac3bc7cdb6a0e6..5582410727cbf5cdb70bb1cba30729d7ebf4aa26 100644 (file)
@@ -411,7 +411,8 @@ extern __printf(3, 0)
 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
 extern __printf(2, 3)
 char *kasprintf(gfp_t gfp, const char *fmt, ...);
-extern char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
+extern __printf(2, 0)
+char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
 
 extern __scanf(2, 3)
 int sscanf(const char *, const char *, ...);
@@ -679,10 +680,10 @@ do {                                                                      \
                __ftrace_vprintk(_THIS_IP_, fmt, vargs);                \
 } while (0)
 
-extern int
+extern __printf(2, 0) int
 __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap);
 
-extern int
+extern __printf(2, 0) int
 __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap);
 
 extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode);
@@ -702,7 +703,7 @@ int trace_printk(const char *fmt, ...)
 {
        return 0;
 }
-static inline int
+static __printf(1, 0) inline int
 ftrace_vprintk(const char *fmt, va_list ap)
 {
        return 0;
index 2d61b909f414f6f61e37ca9c53372d85392242fd..637f67002c5ac6b39536b5cf74a77caf3b1f749f 100644 (file)
@@ -80,8 +80,9 @@ struct kobject {
 
 extern __printf(2, 3)
 int kobject_set_name(struct kobject *kobj, const char *name, ...);
-extern int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
-                                 va_list vargs);
+extern __printf(2, 0)
+int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
+                          va_list vargs);
 
 static inline const char *kobject_name(const struct kobject *kobj)
 {
index 9564fd78c547b6128ddf8304639e2215b6190e3f..05e99b8ef465bcc10ca979b26b68277191951d86 100644 (file)
@@ -734,6 +734,24 @@ static inline bool kvm_arch_has_noncoherent_dma(struct kvm *kvm)
        return false;
 }
 #endif
+#ifdef __KVM_HAVE_ARCH_ASSIGNED_DEVICE
+void kvm_arch_start_assignment(struct kvm *kvm);
+void kvm_arch_end_assignment(struct kvm *kvm);
+bool kvm_arch_has_assigned_device(struct kvm *kvm);
+#else
+static inline void kvm_arch_start_assignment(struct kvm *kvm)
+{
+}
+
+static inline void kvm_arch_end_assignment(struct kvm *kvm)
+{
+}
+
+static inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
+{
+       return false;
+}
+#endif
 
 static inline wait_queue_head_t *kvm_arch_vcpu_wq(struct kvm_vcpu *vcpu)
 {
index 36ce37bcc963c270548989d658caa4f3ce832045..c9cfbcdb8d140e2f136b724501a064a25a766fb3 100644 (file)
@@ -431,6 +431,8 @@ enum {
        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_NOTRIM      = (1 << 24),    /* don't use TRIM */
+       ATA_HORKAGE_MAX_SEC_1024 = (1 << 25),   /* Limit max sects to 1024 */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index 2e872f92dbac0cecc2c5b3a65fbe7ff8678e48d5..bf6f117fcf4d80cb7de6147e86c6ba19fa13febd 100644 (file)
@@ -1002,6 +1002,34 @@ static inline int page_mapped(struct page *page)
        return atomic_read(&(page)->_mapcount) >= 0;
 }
 
+/*
+ * Return true only if the page has been allocated with
+ * ALLOC_NO_WATERMARKS and the low watermark was not
+ * met implying that the system is under some pressure.
+ */
+static inline bool page_is_pfmemalloc(struct page *page)
+{
+       /*
+        * Page index cannot be this large so this must be
+        * a pfmemalloc page.
+        */
+       return page->index == -1UL;
+}
+
+/*
+ * Only to be called by the page allocator on a freshly allocated
+ * page.
+ */
+static inline void set_page_pfmemalloc(struct page *page)
+{
+       page->index = -1UL;
+}
+
+static inline void clear_page_pfmemalloc(struct page *page)
+{
+       page->index = 0;
+}
+
 /*
  * Different kinds of faults, as returned by handle_mm_fault().
  * Used to decide whether a process gets delivered SIGBUS or
index 0038ac7466fd26e7562a026af68632573e3bb0ea..15549578d55998e5497c5da58a50fa1531e132d8 100644 (file)
@@ -63,15 +63,6 @@ struct page {
                union {
                        pgoff_t index;          /* Our offset within mapping. */
                        void *freelist;         /* sl[aou]b first free object */
-                       bool pfmemalloc;        /* If set by the page allocator,
-                                                * ALLOC_NO_WATERMARKS was set
-                                                * and the low watermark was not
-                                                * met implying that the system
-                                                * is under some pressure. The
-                                                * caller should try ensure
-                                                * this page is only used to
-                                                * free other pages.
-                                                */
                };
 
                union {
index c5d52780d6a02fe27ec67cb892b447c43a6beefb..3ba327af055cc43e4d38517fda8557420238f7f0 100644 (file)
@@ -106,6 +106,6 @@ extern void enable_mmiotrace(void);
 extern void disable_mmiotrace(void);
 extern void mmio_trace_rw(struct mmiotrace_rw *rw);
 extern void mmio_trace_mapping(struct mmiotrace_map *map);
-extern int mmio_trace_printk(const char *fmt, va_list args);
+extern __printf(1, 0) int mmio_trace_printk(const char *fmt, va_list args);
 
 #endif /* _LINUX_MMIOTRACE_H */
index 8183d6640ca7ac24ffff5f011f8267c888f251f6..34f25b7bf6421789dc7393f6c3dbc5f4d8877c77 100644 (file)
@@ -189,6 +189,8 @@ struct css_device_id {
 struct acpi_device_id {
        __u8 id[ACPI_ID_LEN];
        kernel_ulong_t driver_data;
+       __u32 cls;
+       __u32 cls_msk;
 };
 
 #define PNP_ID_LEN     8
index d67b1932cc59869cd5c3dc5d24efa5994b368386..3a19c79918e02d37c3e77ed32a88eb9f36bb16c3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/compiler.h>
 #include <linux/cache.h>
 #include <linux/kmod.h>
+#include <linux/init.h>
 #include <linux/elf.h>
 #include <linux/stringify.h>
 #include <linux/kobject.h>
@@ -71,6 +72,89 @@ extern struct module_attribute module_uevent;
 extern int init_module(void);
 extern void cleanup_module(void);
 
+#ifndef MODULE
+/**
+ * module_init() - driver initialization entry point
+ * @x: function to be run at kernel boot time or module insertion
+ *
+ * module_init() will either be called during do_initcalls() (if
+ * builtin) or at module insertion time (if a module).  There can only
+ * be one per module.
+ */
+#define module_init(x) __initcall(x);
+
+/**
+ * module_exit() - driver exit entry point
+ * @x: function to be run when driver is removed
+ *
+ * module_exit() will wrap the driver clean-up code
+ * with cleanup_module() when used with rmmod when
+ * the driver is a module.  If the driver is statically
+ * compiled into the kernel, module_exit() has no effect.
+ * There can only be one per module.
+ */
+#define module_exit(x) __exitcall(x);
+
+#else /* MODULE */
+
+/*
+ * In most cases loadable modules do not need custom
+ * initcall levels. There are still some valid cases where
+ * a driver may be needed early if built in, and does not
+ * matter when built as a loadable module. Like bus
+ * snooping debug drivers.
+ */
+#define early_initcall(fn)             module_init(fn)
+#define core_initcall(fn)              module_init(fn)
+#define core_initcall_sync(fn)         module_init(fn)
+#define postcore_initcall(fn)          module_init(fn)
+#define postcore_initcall_sync(fn)     module_init(fn)
+#define arch_initcall(fn)              module_init(fn)
+#define subsys_initcall(fn)            module_init(fn)
+#define subsys_initcall_sync(fn)       module_init(fn)
+#define fs_initcall(fn)                        module_init(fn)
+#define fs_initcall_sync(fn)           module_init(fn)
+#define rootfs_initcall(fn)            module_init(fn)
+#define device_initcall(fn)            module_init(fn)
+#define device_initcall_sync(fn)       module_init(fn)
+#define late_initcall(fn)              module_init(fn)
+#define late_initcall_sync(fn)         module_init(fn)
+
+#define console_initcall(fn)           module_init(fn)
+#define security_initcall(fn)          module_init(fn)
+
+/* Each module must use one module_init(). */
+#define module_init(initfn)                                    \
+       static inline initcall_t __inittest(void)               \
+       { return initfn; }                                      \
+       int init_module(void) __attribute__((alias(#initfn)));
+
+/* This is only required if you want to be unloadable. */
+#define module_exit(exitfn)                                    \
+       static inline exitcall_t __exittest(void)               \
+       { return exitfn; }                                      \
+       void cleanup_module(void) __attribute__((alias(#exitfn)));
+
+#endif
+
+/* This means "can be init if no module support, otherwise module load
+   may call it." */
+#ifdef CONFIG_MODULES
+#define __init_or_module
+#define __initdata_or_module
+#define __initconst_or_module
+#define __INIT_OR_MODULE       .text
+#define __INITDATA_OR_MODULE   .data
+#define __INITRODATA_OR_MODULE .section ".rodata","a",%progbits
+#else
+#define __init_or_module __init
+#define __initdata_or_module __initdata
+#define __initconst_or_module __initconst
+#define __INIT_OR_MODULE __INIT
+#define __INITDATA_OR_MODULE __INITDATA
+#define __INITRODATA_OR_MODULE __INITRODATA
+#endif /*CONFIG_MODULES*/
+
 /* Archs provide a method of finding the correct exception table. */
 struct exception_table_entry;
 
index f25e2bdd188c94643efc0f3a94c7c67de81897aa..272f42952f3424aa43953b7e3a50b925a93bd465 100644 (file)
@@ -177,11 +177,6 @@ typedef enum {
 #define NAND_OWN_BUFFERS       0x00020000
 /* Chip may not exist, so silence any errors in scan */
 #define NAND_SCAN_SILENT_NODEV 0x00040000
-/*
- * This option could be defined by controller drivers to protect against
- * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers
- */
-#define NAND_USE_BOUNCE_BUFFER 0x00080000
 /*
  * Autodetect nand buswidth with readid/onfi.
  * This suppose the driver will configure the hardware in 8 bits mode
@@ -189,6 +184,11 @@ typedef enum {
  * before calling nand_scan_tail.
  */
 #define NAND_BUSWIDTH_AUTO      0x00080000
+/*
+ * This option could be defined by controller drivers to protect against
+ * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers
+ */
+#define NAND_USE_BOUNCE_BUFFER 0x00100000
 
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
index f91b5ade30c98fe8b03d06bc40deb0c434edb633..874b77228fb96285fb2024f07fa99d1ed7dd6dda 100644 (file)
@@ -292,9 +292,12 @@ static inline void nfs_mark_for_revalidate(struct inode *inode)
        struct nfs_inode *nfsi = NFS_I(inode);
 
        spin_lock(&inode->i_lock);
-       nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+       nfsi->cache_validity |= NFS_INO_INVALID_ATTR |
+                               NFS_INO_REVAL_PAGECACHE |
+                               NFS_INO_INVALID_ACCESS |
+                               NFS_INO_INVALID_ACL;
        if (S_ISDIR(inode->i_mode))
-               nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
+               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
        spin_unlock(&inode->i_lock);
 }
 
index a2ea1491d3dfc487611445490fb10adf9972d777..20bc8e51b16124496326274e84fc12d61996a4fd 100644 (file)
@@ -220,7 +220,7 @@ struct nfs_server {
 #define NFS_CAP_SYMLINKS       (1U << 2)
 #define NFS_CAP_ACLS           (1U << 3)
 #define NFS_CAP_ATOMIC_OPEN    (1U << 4)
-#define NFS_CAP_CHANGE_ATTR    (1U << 5)
+/* #define NFS_CAP_CHANGE_ATTR (1U << 5) */
 #define NFS_CAP_FILEID         (1U << 6)
 #define NFS_CAP_MODE           (1U << 7)
 #define NFS_CAP_NLINK          (1U << 8)
index 4c508549833a53fc76b59ba6a0bda354fc4d051f..cc7dd687a89dd60699ebe28556138e293bcde9bc 100644 (file)
@@ -59,7 +59,7 @@ void of_dma_configure(struct device *dev, struct device_node *np);
 #else /* CONFIG_OF */
 
 static inline int of_driver_match_device(struct device *dev,
-                                        struct device_driver *drv)
+                                        const struct device_driver *drv)
 {
        return 0;
 }
index f34e040b34e9ffbf0abe66b439571ec8902440ca..41c93844fb1d1ed5c0dbad77fe5a409557d66067 100644 (file)
@@ -631,15 +631,19 @@ static inline void ClearPageSlabPfmemalloc(struct page *page)
         1 << PG_private | 1 << PG_private_2 | \
         1 << PG_writeback | 1 << PG_reserved | \
         1 << PG_slab    | 1 << PG_swapcache | 1 << PG_active | \
-        1 << PG_unevictable | __PG_MLOCKED | __PG_HWPOISON | \
+        1 << PG_unevictable | __PG_MLOCKED | \
         __PG_COMPOUND_LOCK)
 
 /*
  * Flags checked when a page is prepped for return by the page allocator.
- * Pages being prepped should not have any flags set.  It they are set,
+ * Pages being prepped should not have these flags set.  It they are set,
  * there has been a kernel bug or struct page corruption.
+ *
+ * __PG_HWPOISON is exceptional because it needs to be kept beyond page's
+ * alloc-free cycle to prevent from reusing the page.
  */
-#define PAGE_FLAGS_CHECK_AT_PREP       ((1 << NR_PAGEFLAGS) - 1)
+#define PAGE_FLAGS_CHECK_AT_PREP       \
+       (((1 << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON)
 
 #define PAGE_FLAGS_PRIVATE                             \
        (1 << PG_private | 1 << PG_private_2)
index b48c3471c254471ed940921ab7bb4832d6f92023..cacaabea8a0950115138c956737c2bd9d7c04a90 100644 (file)
@@ -8,6 +8,7 @@ extern struct page_ext_operations page_owner_ops;
 extern void __reset_page_owner(struct page *page, unsigned int order);
 extern void __set_page_owner(struct page *page,
                        unsigned int order, gfp_t gfp_mask);
+extern gfp_t __get_page_owner_gfp(struct page *page);
 
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -25,6 +26,14 @@ static inline void set_page_owner(struct page *page,
 
        __set_page_owner(page, order, gfp_mask);
 }
+
+static inline gfp_t get_page_owner_gfp(struct page *page)
+{
+       if (likely(!page_owner_inited))
+               return 0;
+
+       return __get_page_owner_gfp(page);
+}
 #else
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -33,6 +42,10 @@ static inline void set_page_owner(struct page *page,
                        unsigned int order, gfp_t gfp_mask)
 {
 }
+static inline gfp_t get_page_owner_gfp(struct page *page)
+{
+       return 0;
+}
 
 #endif /* CONFIG_PAGE_OWNER */
 #endif /* __LINUX_PAGE_OWNER_H */
index 3cc21c9cc1e86ca6a48b23bbd466ff5aa7134e74..9fade5dd2e869219b8ff193e4f9a0bbdd1aac83f 100644 (file)
@@ -4,7 +4,7 @@
  * Arasan Compact Flash host controller platform data header file
  *
  * Copyright (C) 2011 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
+ * Viresh Kumar <vireshk@kernel.org>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 044a124bfbbc6b313d96f187a598fcb1438b8cc6..21b15f6fee2546e520a355b5a1d8cd4835fdc518 100644 (file)
@@ -8,11 +8,19 @@
 #ifndef __MACB_PDATA_H__
 #define __MACB_PDATA_H__
 
+/**
+ * struct macb_platform_data - platform data for MACB Ethernet
+ * @phy_mask:          phy mask passed when register the MDIO bus
+ *                     within the driver
+ * @phy_irq_pin:       PHY IRQ
+ * @is_rmii:           using RMII interface?
+ * @rev_eth_addr:      reverse Ethernet address byte order
+ */
 struct macb_platform_data {
        u32             phy_mask;
-       int             phy_irq_pin;    /* PHY IRQ */
-       u8              is_rmii;        /* using RMII interface? */
-       u8              rev_eth_addr;   /* reverse Ethernet address byte order */
+       int             phy_irq_pin;
+       u8              is_rmii;
+       u8              rev_eth_addr;
 };
 
 #endif /* __MACB_PDATA_H__ */
index 75f70f6ac13778f448a03de3136d32a0ef638b65..e1571efa3f2b28e01642e08f6709d7c7c8dc141a 100644 (file)
@@ -43,7 +43,6 @@ struct esdhc_platform_data {
        enum wp_types wp_type;
        enum cd_types cd_type;
        int max_bus_width;
-       unsigned int f_max;
        bool support_vsel;
        unsigned int delay_line;
 };
index 8dc2fa47a2aa3c095f66f234d2975c5e18e10f53..f4edcb03c40c9f22bbefc708c831c922cfc9fe4f 100644 (file)
@@ -49,6 +49,7 @@ struct davinci_spi_platform_data {
        u8                      num_chipselect;
        u8                      intr_line;
        u8                      *chip_sel;
+       u8                      prescaler_limit;
        bool                    cshold_bug;
        enum dma_event_q        dma_event_q;
 };
diff --git a/include/linux/platform_data/spi-mt65xx.h b/include/linux/platform_data/spi-mt65xx.h
new file mode 100644 (file)
index 0000000..54b0448
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  MTK SPI bus driver definitions
+ *
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Leilk Liu <leilk.liu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ____LINUX_PLATFORM_DATA_SPI_MTK_H
+#define ____LINUX_PLATFORM_DATA_SPI_MTK_H
+
+/* Board specific platform_data */
+struct mtk_chip_config {
+       u32 tx_mlsb;
+       u32 rx_mlsb;
+};
+#endif
index 58b1fec40d37373001a6d46840702d33e70f1001..a6298b27ac99d9197ccd4dac6c04b09f2c5011da 100644 (file)
@@ -122,7 +122,7 @@ static inline __printf(1, 2) __cold
 void early_printk(const char *s, ...) { }
 #endif
 
-typedef int(*printk_func_t)(const char *fmt, va_list args);
+typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args);
 
 #ifdef CONFIG_PRINTK
 asmlinkage __printf(5, 0)
@@ -166,7 +166,7 @@ char *log_buf_addr_get(void);
 u32 log_buf_len_get(void);
 void log_buf_kexec_setup(void);
 void __init setup_log_buf(int early);
-void dump_stack_set_arch_desc(const char *fmt, ...);
+__printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
 void dump_stack_print_info(const char *log_lvl);
 void show_regs_print_info(const char *log_lvl);
 #else
@@ -217,7 +217,7 @@ static inline void setup_log_buf(int early)
 {
 }
 
-static inline void dump_stack_set_arch_desc(const char *fmt, ...)
+static inline __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...)
 {
 }
 
index 0485bab061fd3936a1f53aafefbf87b659df0365..92273776bce6ba9845ab2584644718cbabcb0dd6 100644 (file)
@@ -197,6 +197,7 @@ enum pxa_ssp_type {
        QUARK_X1000_SSP,
        LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */
        LPSS_BYT_SSP,
+       LPSS_SPT_SSP,
 };
 
 struct ssp_device {
index 2c92e1c8e0553cbd71b16c2dea228f75b56bcd5b..aefd997262e4dabdabe2d6c88723455180e01f56 100644 (file)
@@ -9,10 +9,14 @@
 #ifndef _SIRFSOC_RTC_IOBRG_H_
 #define _SIRFSOC_RTC_IOBRG_H_
 
+struct regmap_config;
+
 extern void sirfsoc_rtc_iobrg_besyncing(void);
 
 extern u32 sirfsoc_rtc_iobrg_readl(u32 addr);
 
 extern void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr);
+struct regmap *devm_regmap_init_iobg(struct device *dev,
+                                   const struct regmap_config *config);
 
 #endif
index ae21f1591615e06cec2115563c3f821fe36c868e..04b5ada460b44e4cf8cfdd918ec8572ea8683a8d 100644 (file)
@@ -1522,8 +1522,6 @@ struct task_struct {
 /* hung task detection */
        unsigned long last_switch_count;
 #endif
-/* CPU-specific state of this task */
-       struct thread_struct thread;
 /* filesystem information */
        struct fs_struct *fs;
 /* open file information */
@@ -1778,8 +1776,22 @@ struct task_struct {
        unsigned long   task_state_change;
 #endif
        int pagefault_disabled;
+/* CPU-specific state of this task */
+       struct thread_struct thread;
+/*
+ * WARNING: on x86, 'thread_struct' contains a variable-sized
+ * structure.  It *MUST* be at the end of 'task_struct'.
+ *
+ * Do not put anything below here!
+ */
 };
 
+#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT
+extern int arch_task_struct_size __read_mostly;
+#else
+# define arch_task_struct_size (sizeof(struct task_struct))
+#endif
+
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
 #define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed)
 
index d6cdd6e87d53bcd1b4f390f61f73b1c91b076bdd..9b88536487e667b8727414e4131188db869711d4 100644 (file)
@@ -1602,20 +1602,16 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
        /*
-        * Propagate page->pfmemalloc to the skb if we can. The problem is
-        * that not all callers have unique ownership of the page. If
-        * pfmemalloc is set, we check the mapping as a mapping implies
-        * page->index is set (index and pfmemalloc share space).
-        * If it's a valid mapping, we cannot use page->pfmemalloc but we
-        * do not lose pfmemalloc information as the pages would not be
-        * allocated using __GFP_MEMALLOC.
+        * Propagate page pfmemalloc to the skb if we can. The problem is
+        * that not all callers have unique ownership of the page but rely
+        * on page_is_pfmemalloc doing the right thing(tm).
         */
        frag->page.p              = page;
        frag->page_offset         = off;
        skb_frag_size_set(frag, size);
 
        page = compound_head(page);
-       if (page->pfmemalloc && !page->mapping)
+       if (page_is_pfmemalloc(page))
                skb->pfmemalloc = true;
 }
 
@@ -2263,7 +2259,7 @@ static inline struct page *dev_alloc_page(void)
 static inline void skb_propagate_pfmemalloc(struct page *page,
                                             struct sk_buff *skb)
 {
-       if (page && page->pfmemalloc)
+       if (page_is_pfmemalloc(page))
                skb->pfmemalloc = true;
 }
 
@@ -2884,11 +2880,11 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb)
  *
  * PHY drivers may accept clones of transmitted packets for
  * timestamping via their phy_driver.txtstamp method. These drivers
- * must call this function to return the skb back to the stack, with
- * or without a timestamp.
+ * must call this function to return the skb back to the stack with a
+ * timestamp.
  *
  * @skb: clone of the the original outgoing packet
- * @hwtstamps: hardware time stamps, may be NULL if not available
+ * @hwtstamps: hardware time stamps
  *
  */
 void skb_complete_tx_timestamp(struct sk_buff *skb,
index 3741ba1a652c9716724bbef2ae1e9c12bc82aa8a..edbfc9a5293ee48f981952eb709f0ed13e6b07c8 100644 (file)
@@ -67,10 +67,13 @@ extern void tick_broadcast_control(enum tick_broadcast_mode mode);
 static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { }
 #endif /* BROADCAST */
 
-#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state);
 #else
-static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state) { return 0; }
+static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+{
+       return 0;
+}
 #endif
 
 static inline void tick_broadcast_enable(void)
index 3aa72e64865021ef0efd15c0511fee55a520c19e..6e191e4e6ab637d8924528c61dc551711d085df2 100644 (file)
@@ -145,7 +145,6 @@ static inline void getboottime(struct timespec *ts)
 }
 #endif
 
-#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
 #define ktime_get_real_ts64(ts)        getnstimeofday64(ts)
 
 /*
index 7c9b484735c533ed4243be050d8ad2e8c67d581a..1f6526c76ee84f4068707bd0ecae16aaa25c0759 100644 (file)
@@ -80,6 +80,9 @@
 #define CDC_NCM_TIMER_INTERVAL_MIN             5UL
 #define CDC_NCM_TIMER_INTERVAL_MAX             (U32_MAX / NSEC_PER_USEC)
 
+/* Driver flags */
+#define CDC_NCM_FLAG_NDP_TO_END        0x02            /* NDP is placed at end of frame */
+
 #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
                                       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
 #define cdc_ncm_data_intf_is_mbim(x)  ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
@@ -103,9 +106,11 @@ struct cdc_ncm_ctx {
 
        spinlock_t mtx;
        atomic_t stop;
+       int drvflags;
 
        u32 timer_interval;
        u32 max_ndp_size;
+       struct usb_cdc_ncm_ndp16 *delayed_ndp16;
 
        u32 tx_timer_pending;
        u32 tx_curr_frame_num;
@@ -133,7 +138,7 @@ struct cdc_ncm_ctx {
 };
 
 u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
+int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
 void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
 struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
 int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in);
index 45534da57759a30d4a8c281bda094c8d4921dba3..644bdc61c387581c29a29d20c0cf1c3fc5085830 100644 (file)
@@ -74,8 +74,6 @@ enum rc_filter_type {
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
- * @encode_wakeup: wakeup filtering uses IR encode API, therefore the allowed
- *     wakeup protocols is the set of all raw encoders
  * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
  * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
  * @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols
@@ -136,7 +134,6 @@ struct rc_dev {
        struct input_dev                *input_dev;
        enum rc_driver_type             driver_type;
        bool                            idle;
-       bool                            encode_wakeup;
        u64                             allowed_protocols;
        u64                             enabled_protocols;
        u64                             allowed_wakeup_protocols;
@@ -246,7 +243,6 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
 #define US_TO_NS(usec)         ((usec) * 1000)
 #define MS_TO_US(msec)         ((msec) * 1000)
 #define MS_TO_NS(msec)         ((msec) * 1000 * 1000)
-#define NS_TO_US(nsec)         DIV_ROUND_UP(nsec, 1000L)
 
 void ir_raw_event_handle(struct rc_dev *dev);
 int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
@@ -254,9 +250,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
 int ir_raw_event_store_with_filter(struct rc_dev *dev,
                                struct ir_raw_event *ev);
 void ir_raw_event_set_idle(struct rc_dev *dev, bool idle);
-int ir_raw_encode_scancode(u64 protocols,
-                          const struct rc_scancode_filter *scancode,
-                          struct ir_raw_event *events, unsigned int max);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {
index 22a44c2f596380856acb1bccf95f14d0c2144994..c192e1b46cdc27372dc56ba704aa630ff113dfd6 100644 (file)
@@ -139,6 +139,7 @@ enum vb2_io_modes {
  * @VB2_BUF_STATE_PREPARING:   buffer is being prepared in videobuf
  * @VB2_BUF_STATE_PREPARED:    buffer prepared in videobuf and by the driver
  * @VB2_BUF_STATE_QUEUED:      buffer queued in videobuf, but not in driver
+ * @VB2_BUF_STATE_REQUEUEING:  re-queue a buffer to the driver
  * @VB2_BUF_STATE_ACTIVE:      buffer queued in driver and possibly used
  *                             in a hardware operation
  * @VB2_BUF_STATE_DONE:                buffer returned from driver to videobuf, but
@@ -152,6 +153,7 @@ enum vb2_buffer_state {
        VB2_BUF_STATE_PREPARING,
        VB2_BUF_STATE_PREPARED,
        VB2_BUF_STATE_QUEUED,
+       VB2_BUF_STATE_REQUEUEING,
        VB2_BUF_STATE_ACTIVE,
        VB2_BUF_STATE_DONE,
        VB2_BUF_STATE_ERROR,
index 3ee4c92afd1bd2baf2b90201a9b4af896d020b5f..931738bc5bba3c999ef280f1f68e9256bf445233 100644 (file)
@@ -99,7 +99,6 @@ struct tc_action_ops {
 
 int tcf_hash_search(struct tc_action *a, u32 index);
 void tcf_hash_destroy(struct tc_action *a);
-int tcf_hash_release(struct tc_action *a, int bind);
 u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
 int tcf_hash_check(u32 index, struct tc_action *a, int bind);
 int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
@@ -107,6 +106,13 @@ int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
 void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
 void tcf_hash_insert(struct tc_action *a);
 
+int __tcf_hash_release(struct tc_action *a, bool bind, bool strict);
+
+static inline int tcf_hash_release(struct tc_action *a, bool bind)
+{
+       return __tcf_hash_release(a, bind, false);
+}
+
 int tcf_register_action(struct tc_action_ops *a, unsigned int mask);
 int tcf_unregister_action(struct tc_action_ops *a);
 int tcf_action_destroy(struct list_head *actions, int bind);
index a741678f24a26d712e08775e213b1b1c50c8ca8a..883fe1e7c5a17e982651a68cfb17cbc0bbe5b367 100644 (file)
@@ -4868,6 +4868,23 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
                             struct cfg80211_chan_def *chandef,
                             enum nl80211_iftype iftype);
 
+/**
+ * cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
+ * @wiphy: the wiphy
+ * @chandef: the channel definition
+ * @iftype: interface type
+ *
+ * Return: %true if there is no secondary channel or the secondary channel(s)
+ * can be used for beaconing (i.e. is not a radar channel etc.). This version
+ * also checks if IR-relaxation conditions apply, to allow beaconing under
+ * more permissive conditions.
+ *
+ * Requires the RTNL to be held.
+ */
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+                                  struct cfg80211_chan_def *chandef,
+                                  enum nl80211_iftype iftype);
+
 /*
  * cfg80211_ch_switch_notify - update wdev channel and notify userspace
  * @dev: the device which switched channels
index e1300b3dd597b9a68db7b6dc9c03a8ea238b4e4c..53eead2da74324b47ef8c772663f9bcb4fd1d0e1 100644 (file)
@@ -21,13 +21,11 @@ struct netns_frags {
  * @INET_FRAG_FIRST_IN: first fragment has arrived
  * @INET_FRAG_LAST_IN: final fragment has arrived
  * @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction
- * @INET_FRAG_EVICTED: frag queue is being evicted
  */
 enum {
        INET_FRAG_FIRST_IN      = BIT(0),
        INET_FRAG_LAST_IN       = BIT(1),
        INET_FRAG_COMPLETE      = BIT(2),
-       INET_FRAG_EVICTED       = BIT(3)
 };
 
 /**
@@ -45,6 +43,7 @@ enum {
  * @flags: fragment queue flags
  * @max_size: maximum received fragment size
  * @net: namespace that this frag belongs to
+ * @list_evictor: list of queues to forcefully evict (e.g. due to low memory)
  */
 struct inet_frag_queue {
        spinlock_t              lock;
@@ -59,6 +58,7 @@ struct inet_frag_queue {
        __u8                    flags;
        u16                     max_size;
        struct netns_frags      *net;
+       struct hlist_node       list_evictor;
 };
 
 #define INETFRAGS_HASHSZ       1024
@@ -125,6 +125,11 @@ static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f
                inet_frag_destroy(q, f);
 }
 
+static inline bool inet_frag_evicting(struct inet_frag_queue *q)
+{
+       return !hlist_unhashed(&q->list_evictor);
+}
+
 /* Memory Tracking Functions. */
 
 /* The default percpu_counter batch size is not big enough to scale to
@@ -139,14 +144,14 @@ static inline int frag_mem_limit(struct netns_frags *nf)
        return percpu_counter_read(&nf->mem);
 }
 
-static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i)
+static inline void sub_frag_mem_limit(struct netns_frags *nf, int i)
 {
-       __percpu_counter_add(&q->net->mem, -i, frag_percpu_counter_batch);
+       __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
 }
 
-static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i)
+static inline void add_frag_mem_limit(struct netns_frags *nf, int i)
 {
-       __percpu_counter_add(&q->net->mem, i, frag_percpu_counter_batch);
+       __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
 }
 
 static inline void init_frag_mem_limit(struct netns_frags *nf)
index 0750a186ea635678efe15b2619f32e91f86fde99..d5fe9f2ab6996f0aa9482980ecc4cdc793d63a5a 100644 (file)
@@ -161,6 +161,7 @@ static inline __u8 get_rtconn_flags(struct ipcm_cookie* ipc, struct sock* sk)
 }
 
 /* datagram.c */
+int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
 int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
 
 void ip4_datagram_release_cb(struct sock *sk);
index 49c142bdf01e67b55bcf59c2d1e63f6615783ea1..5fa643b4e8913a35b3a3ead9ad66fa74d368ef70 100644 (file)
@@ -183,7 +183,6 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
 struct fib_table {
        struct hlist_node       tb_hlist;
        u32                     tb_id;
-       int                     tb_default;
        int                     tb_num_default;
        struct rcu_head         rcu;
        unsigned long           *tb_data;
@@ -290,7 +289,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb);
 int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
                        u8 tos, int oif, struct net_device *dev,
                        struct in_device *idev, u32 *itag);
-void fib_select_default(struct fib_result *res);
+void fib_select_default(const struct flowi4 *flp, struct fib_result *res);
 #ifdef CONFIG_IP_ROUTE_CLASSID
 static inline int fib_num_tclassid_users(struct net *net)
 {
index 095433b8a8b03dec4b99057dd7165c9dc6d7846f..37cd3911d5c59e97fe6328a2852ea17040f4dbc3 100644 (file)
@@ -291,7 +291,7 @@ extern unsigned int nf_conntrack_max;
 extern unsigned int nf_conntrack_hash_rnd;
 void init_nf_conntrack_hash_rnd(void);
 
-void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl);
+struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags);
 
 #define NF_CT_STAT_INC(net, count)       __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
index 29d6a94db54d6136b6b380d5817341d2bbe83bce..723b61c82b3f444aee0e7591b8028cb2548e228e 100644 (file)
@@ -68,7 +68,6 @@ struct ct_pcpu {
        spinlock_t              lock;
        struct hlist_nulls_head unconfirmed;
        struct hlist_nulls_head dying;
-       struct hlist_nulls_head tmpl;
 };
 
 struct netns_ct {
index 05a8c1aea25187c1692efcb1e350bb2c7f75a30b..f21f0708ec59ab6fa186657aaa15380590b061f2 100644 (file)
@@ -902,7 +902,7 @@ void sk_stream_kill_queues(struct sock *sk);
 void sk_set_memalloc(struct sock *sk);
 void sk_clear_memalloc(struct sock *sk);
 
-int sk_wait_data(struct sock *sk, long *timeo);
+int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb);
 
 struct request_sock_ops;
 struct timewait_sock_ops;
index 986fddb085796035a44c69e48779ec84393415f8..b0f898e3b2e733307100cd4cf80159bc88972b6d 100644 (file)
@@ -1745,6 +1745,7 @@ struct ib_device {
        char                         node_desc[64];
        __be64                       node_guid;
        u32                          local_dma_lkey;
+       u16                          is_switch:1;
        u8                           node_type;
        u8                           phys_port_cnt;
 
@@ -1823,6 +1824,20 @@ int ib_query_port(struct ib_device *device,
 enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device,
                                               u8 port_num);
 
+/**
+ * rdma_cap_ib_switch - Check if the device is IB switch
+ * @device: Device to check
+ *
+ * Device driver is responsible for setting is_switch bit on
+ * in ib_device structure at init time.
+ *
+ * Return: true if the device is IB switch.
+ */
+static inline bool rdma_cap_ib_switch(const struct ib_device *device)
+{
+       return device->is_switch;
+}
+
 /**
  * rdma_start_port - Return the first valid port number for the device
  * specified
@@ -1833,7 +1848,7 @@ enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device,
  */
 static inline u8 rdma_start_port(const struct ib_device *device)
 {
-       return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
+       return rdma_cap_ib_switch(device) ? 0 : 1;
 }
 
 /**
@@ -1846,8 +1861,7 @@ static inline u8 rdma_start_port(const struct ib_device *device)
  */
 static inline u8 rdma_end_port(const struct ib_device *device)
 {
-       return (device->node_type == RDMA_NODE_IB_SWITCH) ?
-               0 : device->phys_port_cnt;
+       return rdma_cap_ib_switch(device) ? 0 : device->phys_port_cnt;
 }
 
 static inline bool rdma_protocol_ib(const struct ib_device *device, u8 port_num)
index 4942710ef720ea5716e8cc6ebf0df941e22500ba..8d1d7fa67ec48bad6872be07258066f9410eec6e 100644 (file)
@@ -28,7 +28,6 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
                                   u64 * info_out);
 
 extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
-extern void scsi_set_sense_information(u8 *buf, u64 info);
 
 extern int scsi_ioctl_reset(struct scsi_device *, int __user *);
 
index cdb05dd1d4401134fcef914cefaa1338eb629437..d40d3ef25707bd7979a36d9e6e094a394d9f915e 100644 (file)
@@ -119,6 +119,7 @@ extern struct srp_rport *srp_rport_add(struct Scsi_Host *,
 extern void srp_rport_del(struct srp_rport *);
 extern int srp_tmo_valid(int reconnect_delay, int fast_io_fail_tmo,
                         int dev_loss_tmo);
+int srp_parse_tmo(int *tmo, const char *buf);
 extern int srp_reconnect_rport(struct srp_rport *rport);
 extern void srp_start_tl_fail_timers(struct srp_rport *rport);
 extern void srp_remove_host(struct Scsi_Host *);
index 865a141b118b15874e27b0e56473bac8854c4823..427bc41df3aef3a3f931bd94830f027bafea2661 100644 (file)
@@ -141,6 +141,8 @@ struct snd_soc_tplg_ops {
        int io_ops_count;
 };
 
+#ifdef CONFIG_SND_SOC_TOPOLOGY
+
 /* gets a pointer to data from the firmware block header */
 static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
 {
@@ -165,4 +167,14 @@ int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
        const struct snd_soc_tplg_widget_events *events, int num_events,
        u16 event_type);
 
+#else
+
+static inline int snd_soc_tplg_component_remove(struct snd_soc_component *comp,
+                                               u32 index)
+{
+       return 0;
+}
+
+#endif
+
 #endif
index 34117b8b72e49d84fb9477326ad10a490de1060a..0aedbb2c10e0451c162118988d6c070efcd9b629 100644 (file)
@@ -595,6 +595,7 @@ struct iscsi_conn {
        int                     bitmap_id;
        int                     rx_thread_active;
        struct task_struct      *rx_thread;
+       struct completion       rx_login_comp;
        int                     tx_thread_active;
        struct task_struct      *tx_thread;
        /* list_head for session connection list */
index b6fce900a8334613f45f169a0c28802327222f56..fbdd11851725ffa77435b0d3f66cfdfd4f7bb5fb 100644 (file)
@@ -32,7 +32,7 @@
 #ifndef __AMDGPU_DRM_H__
 #define __AMDGPU_DRM_H__
 
-#include <drm/drm.h>
+#include "drm.h"
 
 #define DRM_AMDGPU_GEM_CREATE          0x00
 #define DRM_AMDGPU_GEM_MMAP            0x01
@@ -614,6 +614,8 @@ struct drm_amdgpu_info_device {
        uint32_t vram_type;
        /** video memory bit width*/
        uint32_t vram_bit_width;
+       /* vce harvesting instance */
+       uint32_t vce_harvest_config;
 };
 
 struct drm_amdgpu_info_hw_ip {
index 6e1a2ed116cb1410958f61631a7dc30839652738..db809b722985d3a1a03480cc1e3d36a656af2d2d 100644 (file)
@@ -1070,6 +1070,14 @@ struct drm_i915_reg_read {
        __u64 offset;
        __u64 val; /* Return value */
 };
+/* Known registers:
+ *
+ * Render engine timestamp - 0x2358 + 64bit - gen7+
+ * - Note this register returns an invalid value if using the default
+ *   single instruction 8byte read, in order to workaround that use
+ *   offset (0x2538 | 1) instead.
+ *
+ */
 
 struct drm_i915_reset_stats {
        __u32 ctx_id;
index 1ef76661e1a1b5cc7a1d1021aefd2501f8e5375e..01aa2a8e3f8de1bc368ab53f3f5db472f0329fa7 100644 (file)
@@ -33,7 +33,7 @@
 #ifndef __RADEON_DRM_H__
 #define __RADEON_DRM_H__
 
-#include <drm/drm.h>
+#include "drm.h"
 
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the X server file (radeon_sarea.h)
index 669a1f0b1d976d2f6045b539f18e1fccbadc6809..23cbd34e4ac738de5c1d587be1028b5bca01ef86 100644 (file)
@@ -15,6 +15,7 @@ enum {
        NETCONFA_RP_FILTER,
        NETCONFA_MC_FORWARDING,
        NETCONFA_PROXY_NEIGH,
+       NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
        __NETCONFA_MAX
 };
 #define NETCONFA_MAX   (__NETCONFA_MAX - 1)
index efe3443572baa5a3650d638806fd60ef09a90f68..413417f3707bbfde6375dfc14098bc1e099b5b70 100644 (file)
 #define PCI_MSIX_PBA           8       /* Pending Bit Array offset */
 #define  PCI_MSIX_PBA_BIR      0x00000007 /* BAR index */
 #define  PCI_MSIX_PBA_OFFSET   0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */
 #define PCI_CAP_MSIX_SIZEOF    12      /* size of MSIX registers */
 
 /* MSI-X Table entry format */
index 7bbee79ca2933f518a16f0250e7bbfd0a4e85fe0..ec32293a00db057eb7559c2e7cadce01deb3ef22 100644 (file)
@@ -34,6 +34,7 @@
 /* The feature bitmap for virtio net */
 #define VIRTIO_NET_F_CSUM      0       /* Host handles pkts w/ partial csum */
 #define VIRTIO_NET_F_GUEST_CSUM        1       /* Guest handles pkts w/ partial csum */
+#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2 /* Dynamic offload configuration. */
 #define VIRTIO_NET_F_MAC       5       /* Host has given MAC address. */
 #define VIRTIO_NET_F_GUEST_TSO4        7       /* Guest can handle TSOv4 in. */
 #define VIRTIO_NET_F_GUEST_TSO6        8       /* Guest can handle TSOv6 in. */
@@ -226,4 +227,19 @@ struct virtio_net_ctrl_mq {
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
  #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
 
+/*
+ * Control network offloads
+ *
+ * Reconfigures the network offloads that Guest can handle.
+ *
+ * Available with the VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature bit.
+ *
+ * Command data format matches the feature bit mask exactly.
+ *
+ * See VIRTIO_NET_F_GUEST_* for the list of offloads
+ * that can be enabled/disabled.
+ */
+#define VIRTIO_NET_CTRL_GUEST_OFFLOADS   5
+#define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET        0
+
 #endif /* _LINUX_VIRTIO_NET_H */
index 75301468359f0c558ff8c3c12450301c80cff19a..90007a1abcab144ac3d6ac7d6e6f4001d58abb14 100644 (file)
@@ -157,6 +157,12 @@ struct virtio_pci_common_cfg {
        __le32 queue_used_hi;           /* read-write */
 };
 
+/* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
+struct virtio_pci_cfg_cap {
+       struct virtio_pci_cap cap;
+       __u8 pci_cfg_data[4]; /* Data for BAR access. */
+};
+
 /* Macro versions of offsets for the Old Timers! */
 #define VIRTIO_PCI_CAP_VNDR            0
 #define VIRTIO_PCI_CAP_NEXT            1
index 915980ac68dfa8cc1dc973b8a7e659fc56383c22..c07295969b7e134ec85bf58b72b100949a6462fa 100644 (file)
@@ -31,6 +31,9 @@
  * SUCH DAMAGE.
  *
  * Copyright Rusty Russell IBM Corporation 2007. */
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
 #include <linux/types.h>
 #include <linux/virtio_types.h>
 
@@ -143,7 +146,7 @@ static inline void vring_init(struct vring *vr, unsigned int num, void *p,
        vr->num = num;
        vr->desc = p;
        vr->avail = p + num*sizeof(struct vring_desc);
-       vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__virtio16)
+       vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] + sizeof(__virtio16)
                + align-1) & ~(align - 1));
 }
 
index 12215205ab8d0b11d854dcaa29f00bed48a980c7..247c50bd60f0d067ad8884dbe4574adf0bfcf596 100644 (file)
 #include <linux/types.h>
 #include <sound/asound.h>
 
+#ifndef __KERNEL__
+#error This API is an early revision and not enabled in the current
+#error kernel release, it will be enabled in a future kernel version
+#error with incompatible changes to what is here.
+#endif
+
 /*
  * Maximum number of channels topology kcontrol can represent.
  */
@@ -77,7 +83,7 @@
 #define SND_SOC_TPLG_NUM_TEXTS         16
 
 /* ABI version */
-#define SND_SOC_TPLG_ABI_VERSION       0x2
+#define SND_SOC_TPLG_ABI_VERSION       0x3
 
 /* Max size of TLV data */
 #define SND_SOC_TPLG_TLV_SIZE          32
 #define SND_SOC_TPLG_TYPE_PCM          7
 #define SND_SOC_TPLG_TYPE_MANIFEST     8
 #define SND_SOC_TPLG_TYPE_CODEC_LINK   9
-#define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_CODEC_LINK
+#define SND_SOC_TPLG_TYPE_PDATA                10
+#define SND_SOC_TPLG_TYPE_MAX  SND_SOC_TPLG_TYPE_PDATA
 
 /* vendor block IDs - please add new vendor types to end */
 #define SND_SOC_TPLG_TYPE_VENDOR_FW    1000
 
 /*
  * Block Header.
- * This header preceeds all object and object arrays below.
+ * This header precedes all object and object arrays below.
  */
 struct snd_soc_tplg_hdr {
        __le32 magic;           /* magic number */
@@ -137,11 +144,19 @@ struct snd_soc_tplg_private {
 /*
  * Kcontrol TLV data.
  */
+struct snd_soc_tplg_tlv_dbscale {
+       __le32 min;
+       __le32 step;
+       __le32 mute;
+} __attribute__((packed));
+
 struct snd_soc_tplg_ctl_tlv {
-       __le32 size;    /* in bytes aligned to 4 */
-       __le32 numid;   /* control element numeric identification */
-       __le32 count;   /* number of elem in data array */
-       __le32 data[SND_SOC_TPLG_TLV_SIZE];
+       __le32 size;    /* in bytes of this structure */
+       __le32 type;    /* SNDRV_CTL_TLVT_*, type of TLV */
+       union {
+               __le32 data[SND_SOC_TPLG_TLV_SIZE];
+               struct snd_soc_tplg_tlv_dbscale scale;
+       };
 } __attribute__((packed));
 
 /*
@@ -155,9 +170,11 @@ struct snd_soc_tplg_channel {
 } __attribute__((packed));
 
 /*
- * Kcontrol Operations IDs
+ * Genericl Operations IDs, for binding Kcontrol or Bytes ext ops
+ * Kcontrol ops need get/put/info.
+ * Bytes ext ops need get/put.
  */
-struct snd_soc_tplg_kcontrol_ops_id {
+struct snd_soc_tplg_io_ops {
        __le32 get;
        __le32 put;
        __le32 info;
@@ -171,8 +188,8 @@ struct snd_soc_tplg_ctl_hdr {
        __le32 type;
        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        __le32 access;
-       struct snd_soc_tplg_kcontrol_ops_id ops;
-       __le32 tlv_size;        /* non zero means control has TLV data */
+       struct snd_soc_tplg_io_ops ops;
+       struct snd_soc_tplg_ctl_tlv tlv;
 } __attribute__((packed));
 
 /*
@@ -222,7 +239,7 @@ struct snd_soc_tplg_stream_config {
 /*
  * Manifest. List totals for each payload type. Not used in parsing, but will
  * be passed to the component driver before any other objects in order for any
- * global componnent resource allocations.
+ * global component resource allocations.
  *
  * File block representation for manifest :-
  * +-----------------------------------+----+
@@ -238,6 +255,7 @@ struct snd_soc_tplg_manifest {
        __le32 graph_elems;     /* number of graph elements */
        __le32 dai_elems;       /* number of DAI elements */
        __le32 dai_link_elems;  /* number of DAI link elements */
+       struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
 /*
@@ -259,7 +277,6 @@ struct snd_soc_tplg_mixer_control {
        __le32 invert;
        __le32 num_channels;
        struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
-       struct snd_soc_tplg_ctl_tlv tlv;
        struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
@@ -303,6 +320,7 @@ struct snd_soc_tplg_bytes_control {
        __le32 mask;
        __le32 base;
        __le32 num_regs;
+       struct snd_soc_tplg_io_ops ext_ops;
        struct snd_soc_tplg_private priv;
 } __attribute__((packed));
 
@@ -347,6 +365,7 @@ struct snd_soc_tplg_dapm_widget {
        __le32 reg;             /* negative reg = no direct dapm */
        __le32 shift;           /* bits to shift */
        __le32 mask;            /* non-shifted mask */
+       __le32 subseq;          /* sort within widget type */
        __u32 invert;           /* invert the power bit */
        __u32 ignore_suspend;   /* kept enabled over suspend */
        __u16 event_flags;
index c5d5626289cee3a46f7e1b7d2441ca0496ba4471..56506553d4d80dff814b75f45db6db280fd0dea7 100644 (file)
@@ -656,7 +656,7 @@ asmlinkage __visible void __init start_kernel(void)
        key_init();
        security_init();
        dbg_late_init();
-       vfs_caches_init(totalram_pages);
+       vfs_caches_init();
        signals_init();
        /* rootfs populating might need page-writeback */
        page_writeback_init();
index a24ba9fe5bb8892dfaa7452fe78f9ef68d1d97fc..161a1807e6efb0fe8e773c41dafc8b4a76b38f71 100644 (file)
@@ -142,7 +142,6 @@ static int msg_insert(struct msg_msg *msg, struct mqueue_inode_info *info)
                if (!leaf)
                        return -ENOMEM;
                INIT_LIST_HEAD(&leaf->msg_list);
-               info->qsize += sizeof(*leaf);
        }
        leaf->priority = msg->m_type;
        rb_link_node(&leaf->rb_node, parent, p);
@@ -187,7 +186,6 @@ try_again:
                             "lazy leaf delete!\n");
                rb_erase(&leaf->rb_node, &info->msg_tree);
                if (info->node_cache) {
-                       info->qsize -= sizeof(*leaf);
                        kfree(leaf);
                } else {
                        info->node_cache = leaf;
@@ -200,7 +198,6 @@ try_again:
                if (list_empty(&leaf->msg_list)) {
                        rb_erase(&leaf->rb_node, &info->msg_tree);
                        if (info->node_cache) {
-                               info->qsize -= sizeof(*leaf);
                                kfree(leaf);
                        } else {
                                info->node_cache = leaf;
@@ -1034,7 +1031,6 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
                /* Save our speculative allocation into the cache */
                INIT_LIST_HEAD(&new_leaf->msg_list);
                info->node_cache = new_leaf;
-               info->qsize += sizeof(*new_leaf);
                new_leaf = NULL;
        } else {
                kfree(new_leaf);
@@ -1142,7 +1138,6 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
                /* Save our speculative allocation into the cache */
                INIT_LIST_HEAD(&new_leaf->msg_list);
                info->node_cache = new_leaf;
-               info->qsize += sizeof(*new_leaf);
        } else {
                kfree(new_leaf);
        }
index bc3d530cb23efacb2e5695ad85a9bd3898524fa2..b471e5a3863ddbca70f2bf4dee22f40df0345fbe 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -252,6 +252,16 @@ static void sem_rcu_free(struct rcu_head *head)
        ipc_rcu_free(head);
 }
 
+/*
+ * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they
+ * are only control barriers.
+ * The code must pair with spin_unlock(&sem->lock) or
+ * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient.
+ *
+ * smp_rmb() is sufficient, as writes cannot pass the control barrier.
+ */
+#define ipc_smp_acquire__after_spin_is_unlocked()      smp_rmb()
+
 /*
  * Wait until all currently ongoing simple ops have completed.
  * Caller must own sem_perm.lock.
@@ -275,6 +285,7 @@ static void sem_wait_array(struct sem_array *sma)
                sem = sma->sem_base + i;
                spin_unlock_wait(&sem->lock);
        }
+       ipc_smp_acquire__after_spin_is_unlocked();
 }
 
 /*
@@ -327,13 +338,12 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                /* Then check that the global lock is free */
                if (!spin_is_locked(&sma->sem_perm.lock)) {
                        /*
-                        * The ipc object lock check must be visible on all
-                        * cores before rechecking the complex count.  Otherwise
-                        * we can race with  another thread that does:
+                        * We need a memory barrier with acquire semantics,
+                        * otherwise we can race with another thread that does:
                         *      complex_count++;
                         *      spin_unlock(sem_perm.lock);
                         */
-                       smp_rmb();
+                       ipc_smp_acquire__after_spin_is_unlocked();
 
                        /*
                         * Now repeat the test of complex_count:
@@ -2074,17 +2084,28 @@ void exit_sem(struct task_struct *tsk)
                rcu_read_lock();
                un = list_entry_rcu(ulp->list_proc.next,
                                    struct sem_undo, list_proc);
-               if (&un->list_proc == &ulp->list_proc)
-                       semid = -1;
-                else
-                       semid = un->semid;
+               if (&un->list_proc == &ulp->list_proc) {
+                       /*
+                        * We must wait for freeary() before freeing this ulp,
+                        * in case we raced with last sem_undo. There is a small
+                        * possibility where we exit while freeary() didn't
+                        * finish unlocking sem_undo_list.
+                        */
+                       spin_unlock_wait(&ulp->lock);
+                       rcu_read_unlock();
+                       break;
+               }
+               spin_lock(&ulp->lock);
+               semid = un->semid;
+               spin_unlock(&ulp->lock);
 
+               /* exit_sem raced with IPC_RMID, nothing to do */
                if (semid == -1) {
                        rcu_read_unlock();
-                       break;
+                       continue;
                }
 
-               sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid);
+               sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, semid);
                /* exit_sem raced with IPC_RMID, nothing to do */
                if (IS_ERR(sma)) {
                        rcu_read_unlock();
@@ -2112,9 +2133,11 @@ void exit_sem(struct task_struct *tsk)
                ipc_assert_locked_object(&sma->sem_perm);
                list_del(&un->list_id);
 
-               spin_lock(&ulp->lock);
+               /* we are the last process using this ulp, acquiring ulp->lock
+                * isn't required. Besides that, we are also protected against
+                * IPC_RMID as we hold sma->sem_perm lock now
+                */
                list_del_rcu(&un->list_proc);
-               spin_unlock(&ulp->lock);
 
                /* perform adjustments registered in un */
                for (i = 0; i < sma->sem_nsems; i++) {
index 06e5cf2fe019faee43aa9f8ca9f17cad4973b74d..4aef24d91b633e12275cea64a380df4543fc796b 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -545,7 +545,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
                if  ((shmflg & SHM_NORESERVE) &&
                                sysctl_overcommit_memory != OVERCOMMIT_NEVER)
                        acctflag = VM_NORESERVE;
-               file = shmem_file_setup(name, size, acctflag);
+               file = shmem_kernel_file_setup(name, size, acctflag);
        }
        error = PTR_ERR(file);
        if (IS_ERR(file))
index 09c65640cad6156f0ea702bc32ba9847b9465249..e85bdfd15fedd4c8fed46818edae6191673bff07 100644 (file)
@@ -1021,8 +1021,7 @@ static int audit_log_single_execve_arg(struct audit_context *context,
         * for strings that are too long, we should not have created
         * any.
         */
-       if (unlikely((len == 0) || len > MAX_ARG_STRLEN - 1)) {
-               WARN_ON(1);
+       if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
                send_sig(SIGKILL, current, 0);
                return -1;
        }
index 9c9c9fab16cc3610afa76a6c467780482b35b0be..5644ec5582b93a600accc90c9211c618cd3735fb 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/suspend.h>
 #include <linux/lockdep.h>
 #include <linux/tick.h>
+#include <linux/irq.h>
 #include <trace/events/power.h>
 
 #include "smpboot.h"
@@ -392,13 +393,19 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        smpboot_park_threads(cpu);
 
        /*
-        * So now all preempt/rcu users must observe !cpu_active().
+        * Prevent irq alloc/free while the dying cpu reorganizes the
+        * interrupt affinities.
         */
+       irq_lock_sparse();
 
+       /*
+        * So now all preempt/rcu users must observe !cpu_active().
+        */
        err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
        if (err) {
                /* CPU didn't die: tell everyone.  Can't complain. */
                cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
+               irq_unlock_sparse();
                goto out_release;
        }
        BUG_ON(cpu_online(cpu));
@@ -415,6 +422,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */
        per_cpu(cpu_dead_idle, cpu) = false;
 
+       /* Interrupts are moved away from the dying cpu, reenable alloc/free */
+       irq_unlock_sparse();
+
        hotplug_cpu__broadcast_tick_pull(cpu);
        /* This actually kills the CPU. */
        __cpu_die(cpu);
@@ -519,6 +529,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
 
        /* Arch-specific enabling code. */
        ret = __cpu_up(cpu, idle);
+
        if (ret != 0)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
index ee14e3a35a2994399edf176e7775e778c395e592..f0acff0f66c91380412dcbc1c899c94b1d3236b0 100644 (file)
@@ -1223,7 +1223,7 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
        spin_unlock_irq(&callback_lock);
 
        /* use trialcs->mems_allowed as a temp variable */
-       update_nodemasks_hier(cs, &cs->mems_allowed);
+       update_nodemasks_hier(cs, &trialcs->mems_allowed);
 done:
        return retval;
 }
index e965cfae420725645349c4facd145828e4e59d13..e6feb51141340a99a248fea0ad1dc17402b0dbdb 100644 (file)
@@ -1868,8 +1868,6 @@ event_sched_in(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
-       event->tstamp_running += tstamp - event->tstamp_stopped;
-
        perf_set_shadow_time(event, ctx, tstamp);
 
        perf_log_itrace_start(event);
@@ -1881,6 +1879,8 @@ event_sched_in(struct perf_event *event,
                goto out;
        }
 
+       event->tstamp_running += tstamp - event->tstamp_stopped;
+
        if (!is_software_event(event))
                cpuctx->active_oncpu++;
        if (!ctx->nr_active++)
@@ -3958,28 +3958,21 @@ static void perf_event_for_each(struct perf_event *event,
                perf_event_for_each_child(sibling, func);
 }
 
-static int perf_event_period(struct perf_event *event, u64 __user *arg)
-{
-       struct perf_event_context *ctx = event->ctx;
-       int ret = 0, active;
+struct period_event {
+       struct perf_event *event;
        u64 value;
+};
 
-       if (!is_sampling_event(event))
-               return -EINVAL;
-
-       if (copy_from_user(&value, arg, sizeof(value)))
-               return -EFAULT;
-
-       if (!value)
-               return -EINVAL;
+static int __perf_event_period(void *info)
+{
+       struct period_event *pe = info;
+       struct perf_event *event = pe->event;
+       struct perf_event_context *ctx = event->ctx;
+       u64 value = pe->value;
+       bool active;
 
-       raw_spin_lock_irq(&ctx->lock);
+       raw_spin_lock(&ctx->lock);
        if (event->attr.freq) {
-               if (value > sysctl_perf_event_sample_rate) {
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-
                event->attr.sample_freq = value;
        } else {
                event->attr.sample_period = value;
@@ -3998,11 +3991,53 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
                event->pmu->start(event, PERF_EF_RELOAD);
                perf_pmu_enable(ctx->pmu);
        }
+       raw_spin_unlock(&ctx->lock);
 
-unlock:
+       return 0;
+}
+
+static int perf_event_period(struct perf_event *event, u64 __user *arg)
+{
+       struct period_event pe = { .event = event, };
+       struct perf_event_context *ctx = event->ctx;
+       struct task_struct *task;
+       u64 value;
+
+       if (!is_sampling_event(event))
+               return -EINVAL;
+
+       if (copy_from_user(&value, arg, sizeof(value)))
+               return -EFAULT;
+
+       if (!value)
+               return -EINVAL;
+
+       if (event->attr.freq && value > sysctl_perf_event_sample_rate)
+               return -EINVAL;
+
+       task = ctx->task;
+       pe.value = value;
+
+       if (!task) {
+               cpu_function_call(event->cpu, __perf_event_period, &pe);
+               return 0;
+       }
+
+retry:
+       if (!task_function_call(task, __perf_event_period, &pe))
+               return 0;
+
+       raw_spin_lock_irq(&ctx->lock);
+       if (ctx->is_active) {
+               raw_spin_unlock_irq(&ctx->lock);
+               task = ctx->task;
+               goto retry;
+       }
+
+       __perf_event_period(&pe);
        raw_spin_unlock_irq(&ctx->lock);
 
-       return ret;
+       return 0;
 }
 
 static const struct file_operations perf_fops;
@@ -4358,14 +4393,6 @@ static void ring_buffer_wakeup(struct perf_event *event)
        rcu_read_unlock();
 }
 
-static void rb_free_rcu(struct rcu_head *rcu_head)
-{
-       struct ring_buffer *rb;
-
-       rb = container_of(rcu_head, struct ring_buffer, rcu_head);
-       rb_free(rb);
-}
-
 struct ring_buffer *ring_buffer_get(struct perf_event *event)
 {
        struct ring_buffer *rb;
@@ -4748,12 +4775,20 @@ static const struct file_operations perf_fops = {
  * to user-space before waking everybody up.
  */
 
+static inline struct fasync_struct **perf_event_fasync(struct perf_event *event)
+{
+       /* only the parent has fasync state */
+       if (event->parent)
+               event = event->parent;
+       return &event->fasync;
+}
+
 void perf_event_wakeup(struct perf_event *event)
 {
        ring_buffer_wakeup(event);
 
        if (event->pending_kill) {
-               kill_fasync(&event->fasync, SIGIO, event->pending_kill);
+               kill_fasync(perf_event_fasync(event), SIGIO, event->pending_kill);
                event->pending_kill = 0;
        }
 }
@@ -6132,7 +6167,7 @@ static int __perf_event_overflow(struct perf_event *event,
        else
                perf_event_output(event, data, regs);
 
-       if (event->fasync && event->pending_kill) {
+       if (*perf_event_fasync(event) && event->pending_kill) {
                event->pending_wakeup = 1;
                irq_work_queue(&event->pending);
        }
index 2deb24c7a40dd979313eb1fcff58044d2d948888..2bbad9c1274c3199338e653bbb5c8bd640815fa7 100644 (file)
@@ -11,6 +11,7 @@
 struct ring_buffer {
        atomic_t                        refcount;
        struct rcu_head                 rcu_head;
+       struct irq_work                 irq_work;
 #ifdef CONFIG_PERF_USE_VMALLOC
        struct work_struct              work;
        int                             page_order;     /* allocation order  */
@@ -55,6 +56,15 @@ struct ring_buffer {
 };
 
 extern void rb_free(struct ring_buffer *rb);
+
+static inline void rb_free_rcu(struct rcu_head *rcu_head)
+{
+       struct ring_buffer *rb;
+
+       rb = container_of(rcu_head, struct ring_buffer, rcu_head);
+       rb_free(rb);
+}
+
 extern struct ring_buffer *
 rb_alloc(int nr_pages, long watermark, int cpu, int flags);
 extern void perf_event_wakeup(struct perf_event *event);
index 96472824a752f76fe651ec1bfb7ab7a52411a12c..c8aa3f75bc4db8ad7a2242aae6406bfd6f86f8c5 100644 (file)
@@ -221,6 +221,8 @@ void perf_output_end(struct perf_output_handle *handle)
        rcu_read_unlock();
 }
 
+static void rb_irq_work(struct irq_work *work);
+
 static void
 ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
 {
@@ -241,6 +243,16 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
 
        INIT_LIST_HEAD(&rb->event_list);
        spin_lock_init(&rb->event_lock);
+       init_irq_work(&rb->irq_work, rb_irq_work);
+}
+
+static void ring_buffer_put_async(struct ring_buffer *rb)
+{
+       if (!atomic_dec_and_test(&rb->refcount))
+               return;
+
+       rb->rcu_head.next = (void *)rb;
+       irq_work_queue(&rb->irq_work);
 }
 
 /*
@@ -319,7 +331,7 @@ err_put:
        rb_free_aux(rb);
 
 err:
-       ring_buffer_put(rb);
+       ring_buffer_put_async(rb);
        handle->event = NULL;
 
        return NULL;
@@ -370,7 +382,7 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size,
 
        local_set(&rb->aux_nest, 0);
        rb_free_aux(rb);
-       ring_buffer_put(rb);
+       ring_buffer_put_async(rb);
 }
 
 /*
@@ -547,17 +559,30 @@ static void __rb_free_aux(struct ring_buffer *rb)
                rb->aux_priv = NULL;
        }
 
-       for (pg = 0; pg < rb->aux_nr_pages; pg++)
-               rb_free_aux_page(rb, pg);
+       if (rb->aux_nr_pages) {
+               for (pg = 0; pg < rb->aux_nr_pages; pg++)
+                       rb_free_aux_page(rb, pg);
 
-       kfree(rb->aux_pages);
-       rb->aux_nr_pages = 0;
+               kfree(rb->aux_pages);
+               rb->aux_nr_pages = 0;
+       }
 }
 
 void rb_free_aux(struct ring_buffer *rb)
 {
        if (atomic_dec_and_test(&rb->aux_refcount))
+               irq_work_queue(&rb->irq_work);
+}
+
+static void rb_irq_work(struct irq_work *work)
+{
+       struct ring_buffer *rb = container_of(work, struct ring_buffer, irq_work);
+
+       if (!atomic_read(&rb->aux_refcount))
                __rb_free_aux(rb);
+
+       if (rb->rcu_head.next == (void *)rb)
+               call_rcu(&rb->rcu_head, rb_free_rcu);
 }
 
 #ifndef CONFIG_PERF_USE_VMALLOC
index 1bfefc6f96a4ea92507741cf1e935c6dab04c2b1..dbd9b8d7b7cc2baa8c425bf35191ce8dfd117ecf 100644 (file)
@@ -287,6 +287,11 @@ static void set_max_threads(unsigned int max_threads_suggested)
        max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS);
 }
 
+#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT
+/* Initialized by the architecture: */
+int arch_task_struct_size __read_mostly;
+#endif
+
 void __init fork_init(void)
 {
 #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
@@ -295,7 +300,7 @@ void __init fork_init(void)
 #endif
        /* create a slab on which task_structs can be allocated */
        task_struct_cachep =
-               kmem_cache_create("task_struct", sizeof(struct task_struct),
+               kmem_cache_create("task_struct", arch_task_struct_size,
                        ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);
 #endif
 
index 27f4332c7f84ea8b3d7ec8bb3466a64f225a8487..ae216824e8ca9224c4b76f225ef58d664a3e1726 100644 (file)
@@ -984,6 +984,23 @@ int irq_chip_set_affinity_parent(struct irq_data *data,
        return -ENOSYS;
 }
 
+/**
+ * irq_chip_set_type_parent - Set IRQ type on the parent interrupt
+ * @data:      Pointer to interrupt specific data
+ * @type:      IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
+ *
+ * Conditional, as the underlying parent chip might not implement it.
+ */
+int irq_chip_set_type_parent(struct irq_data *data, unsigned int type)
+{
+       data = data->parent_data;
+
+       if (data->chip->irq_set_type)
+               return data->chip->irq_set_type(data, type);
+
+       return -ENOSYS;
+}
+
 /**
  * irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware
  * @data:      Pointer to interrupt specific data
@@ -997,7 +1014,7 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)
                if (data->chip && data->chip->irq_retrigger)
                        return data->chip->irq_retrigger(data);
 
-       return -ENOSYS;
+       return 0;
 }
 
 /**
index 4834ee828c41e8ee9dd8e8e4fb15e03e66c037e1..61008b8433ab78f5364ac2512d956fd554614690 100644 (file)
@@ -76,12 +76,8 @@ extern void unmask_threaded_irq(struct irq_desc *desc);
 
 #ifdef CONFIG_SPARSE_IRQ
 static inline void irq_mark_irq(unsigned int irq) { }
-extern void irq_lock_sparse(void);
-extern void irq_unlock_sparse(void);
 #else
 extern void irq_mark_irq(unsigned int irq);
-static inline void irq_lock_sparse(void) { }
-static inline void irq_unlock_sparse(void) { }
 #endif
 
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
index 9065107f083e90e3fbd3c38f2fbc164d11ff2b3c..7a5237a1bce5b5626d74cdb377f8e5a900d06f7a 100644 (file)
@@ -75,13 +75,21 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)
                    !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
 #ifdef CONFIG_HARDIRQS_SW_RESEND
                        /*
-                        * If the interrupt has a parent irq and runs
-                        * in the thread context of the parent irq,
-                        * retrigger the parent.
+                        * If the interrupt is running in the thread
+                        * context of the parent irq we need to be
+                        * careful, because we cannot trigger it
+                        * directly.
                         */
-                       if (desc->parent_irq &&
-                           irq_settings_is_nested_thread(desc))
+                       if (irq_settings_is_nested_thread(desc)) {
+                               /*
+                                * If the parent_irq is valid, we
+                                * retrigger the parent, otherwise we
+                                * do nothing.
+                                */
+                               if (!desc->parent_irq)
+                                       return;
                                irq = desc->parent_irq;
+                       }
                        /* Set it pending and activate the softirq: */
                        set_bit(irq, irqs_resend);
                        tasklet_schedule(&resend_tasklet);
index 10e489c448fe4e934e2c203ca2aa7a8d0679bb5e..fdea0bee7b5a4d5e2fcf43ee3b92e1a37dea6c71 100644 (file)
@@ -97,6 +97,7 @@ bool kthread_should_park(void)
 {
        return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
 }
+EXPORT_SYMBOL_GPL(kthread_should_park);
 
 /**
  * kthread_freezable_should_stop - should this freezable kthread return now?
@@ -171,6 +172,7 @@ void kthread_parkme(void)
 {
        __kthread_parkme(to_kthread(current));
 }
+EXPORT_SYMBOL_GPL(kthread_parkme);
 
 static int kthread(void *_create)
 {
@@ -411,6 +413,7 @@ void kthread_unpark(struct task_struct *k)
        if (kthread)
                __kthread_unpark(k, kthread);
 }
+EXPORT_SYMBOL_GPL(kthread_unpark);
 
 /**
  * kthread_park - park a thread created by kthread_create().
@@ -441,6 +444,7 @@ int kthread_park(struct task_struct *k)
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(kthread_park);
 
 /**
  * kthread_stop - stop a thread created by kthread_create().
index 04ab18151cc8fa174a5859124ee07c144f33d505..df19ae4debd09c134d438b57e4ead7c71462c2b6 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/hash.h>
 #include <linux/bootmem.h>
+#include <linux/debug_locks.h>
 
 /*
  * Implement paravirt qspinlocks; the general idea is to halt the vcpus instead
@@ -286,15 +287,23 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
 {
        struct __qspinlock *l = (void *)lock;
        struct pv_node *node;
+       u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
 
        /*
         * We must not unlock if SLOW, because in that case we must first
         * unhash. Otherwise it would be possible to have multiple @lock
         * entries, which would be BAD.
         */
-       if (likely(cmpxchg(&l->locked, _Q_LOCKED_VAL, 0) == _Q_LOCKED_VAL))
+       if (likely(lockval == _Q_LOCKED_VAL))
                return;
 
+       if (unlikely(lockval != _Q_SLOW_VAL)) {
+               if (debug_locks_silent)
+                       return;
+               WARN(1, "pvqspinlock: lock %p has corrupted value 0x%x!\n", lock, atomic_read(&lock->val));
+               return;
+       }
+
        /*
         * Since the above failed to release, this must be the SLOW path.
         * Therefore start by looking up the blocked node and unhashing it.
index 3e0e19763d246a998acb109c6979e4df593e3958..b86b7bf1be388d72fe92fb6038b4a67b4710df1f 100644 (file)
@@ -602,13 +602,16 @@ const struct kernel_symbol *find_symbol(const char *name,
 }
 EXPORT_SYMBOL_GPL(find_symbol);
 
-/* Search for module by name: must hold module_mutex. */
+/*
+ * Search for module by name: must hold module_mutex (or preempt disabled
+ * for read-only access).
+ */
 static struct module *find_module_all(const char *name, size_t len,
                                      bool even_unformed)
 {
        struct module *mod;
 
-       module_assert_mutex();
+       module_assert_mutex_or_preempt();
 
        list_for_each_entry(mod, &modules, list) {
                if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
@@ -621,6 +624,7 @@ static struct module *find_module_all(const char *name, size_t len,
 
 struct module *find_module(const char *name)
 {
+       module_assert_mutex();
        return find_module_all(name, strlen(name), false);
 }
 EXPORT_SYMBOL_GPL(find_module);
@@ -3557,6 +3561,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
        mutex_lock(&module_mutex);
        /* Unlink carefully: kallsyms could be walking list. */
        list_del_rcu(&mod->list);
+       mod_tree_remove(mod);
        wake_up_all(&module_wq);
        /* Wait for RCU-sched synchronizing before releasing mod->list. */
        synchronize_sched();
index 90552aab5f2dd076c147c73cc6f9ff59aabb7af6..fed052a1bc9f5792c7cb856336f2093e75aa2432 100644 (file)
@@ -504,13 +504,13 @@ int region_is_ram(resource_size_t start, unsigned long size)
 {
        struct resource *p;
        resource_size_t end = start + size - 1;
-       int flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        const char *name = "System RAM";
        int ret = -1;
 
        read_lock(&resource_lock);
        for (p = iomem_resource.child; p ; p = p->sibling) {
-               if (end < p->start)
+               if (p->end < start)
                        continue;
 
                if (p->start <= start && end <= p->end) {
@@ -521,7 +521,7 @@ int region_is_ram(resource_size_t start, unsigned long size)
                                ret = 1;
                        break;
                }
-               if (p->end < start)
+               if (end < p->start)
                        break;  /* not found */
        }
        read_unlock(&resource_lock);
index 65c8f3ebdc3c5d58d148780c84c90fe54dc6e4dc..d113c3ba8bc44b4f50a12e9c055cb70b63a632fc 100644 (file)
@@ -3683,7 +3683,7 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
        cfs_rq->throttled = 1;
        cfs_rq->throttled_clock = rq_clock(rq);
        raw_spin_lock(&cfs_b->lock);
-       empty = list_empty(&cfs_rq->throttled_list);
+       empty = list_empty(&cfs_b->throttled_cfs_rq);
 
        /*
         * Add to the _head_ of the list, so that an already-started
index 836df8dac6ccd1230f21d20dc610429538cc59a1..0f6bbbe77b46c092d0de31e0c9eec8a0f17e6791 100644 (file)
@@ -2748,12 +2748,15 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
-               if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
+               if (from->si_signo == SIGBUS &&
+                   (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 #endif
 #ifdef SEGV_BNDERR
-               err |= __put_user(from->si_lower, &to->si_lower);
-               err |= __put_user(from->si_upper, &to->si_upper);
+               if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) {
+                       err |= __put_user(from->si_lower, &to->si_lower);
+                       err |= __put_user(from->si_upper, &to->si_upper);
+               }
 #endif
                break;
        case __SI_CHLD:
@@ -3017,7 +3020,7 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
 {
-       siginfo_t info;
+       siginfo_t info = {};
        int ret = copy_siginfo_from_user32(&info, uinfo);
        if (unlikely(ret))
                return ret;
@@ -3061,7 +3064,7 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
 {
-       siginfo_t info;
+       siginfo_t info = {};
 
        if (copy_siginfo_from_user32(&info, uinfo))
                return -EFAULT;
index 08ccc3da3ca086366eadaae89f46e0604099d661..50eb107f119877ab0762bb671a69cf9c0cd418bc 100644 (file)
@@ -120,19 +120,25 @@ static int __clockevents_switch_state(struct clock_event_device *dev,
                /* The clockevent device is getting replaced. Shut it down. */
 
        case CLOCK_EVT_STATE_SHUTDOWN:
-               return dev->set_state_shutdown(dev);
+               if (dev->set_state_shutdown)
+                       return dev->set_state_shutdown(dev);
+               return 0;
 
        case CLOCK_EVT_STATE_PERIODIC:
                /* Core internal bug */
                if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
                        return -ENOSYS;
-               return dev->set_state_periodic(dev);
+               if (dev->set_state_periodic)
+                       return dev->set_state_periodic(dev);
+               return 0;
 
        case CLOCK_EVT_STATE_ONESHOT:
                /* Core internal bug */
                if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
                        return -ENOSYS;
-               return dev->set_state_oneshot(dev);
+               if (dev->set_state_oneshot)
+                       return dev->set_state_oneshot(dev);
+               return 0;
 
        case CLOCK_EVT_STATE_ONESHOT_STOPPED:
                /* Core internal bug */
@@ -471,18 +477,6 @@ static int clockevents_sanity_check(struct clock_event_device *dev)
        if (dev->features & CLOCK_EVT_FEAT_DUMMY)
                return 0;
 
-       /* New state-specific callbacks */
-       if (!dev->set_state_shutdown)
-               return -EINVAL;
-
-       if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
-           !dev->set_state_periodic)
-               return -EINVAL;
-
-       if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) &&
-           !dev->set_state_oneshot)
-               return -EINVAL;
-
        return 0;
 }
 
index d39f32cdd1b59cca97066430442e3aa054cc9eed..f6aae7977824ab7595950e378c2dd0f0bbe0256d 100644 (file)
@@ -159,7 +159,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
 {
        struct clock_event_device *bc = tick_broadcast_device.evtdev;
        unsigned long flags;
-       int ret;
+       int ret = 0;
 
        raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
 
@@ -221,13 +221,14 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
                         * If we kept the cpu in the broadcast mask,
                         * tell the caller to leave the per cpu device
                         * in shutdown state. The periodic interrupt
-                        * is delivered by the broadcast device.
+                        * is delivered by the broadcast device, if
+                        * the broadcast device exists and is not
+                        * hrtimer based.
                         */
-                       ret = cpumask_test_cpu(cpu, tick_broadcast_mask);
+                       if (bc && !(bc->features & CLOCK_EVT_FEAT_HRTIMER))
+                               ret = cpumask_test_cpu(cpu, tick_broadcast_mask);
                        break;
                default:
-                       /* Nothing to do */
-                       ret = 0;
                        break;
                }
        }
@@ -265,8 +266,22 @@ static bool tick_do_broadcast(struct cpumask *mask)
         * Check, if the current cpu is in the mask
         */
        if (cpumask_test_cpu(cpu, mask)) {
+               struct clock_event_device *bc = tick_broadcast_device.evtdev;
+
                cpumask_clear_cpu(cpu, mask);
-               local = true;
+               /*
+                * We only run the local handler, if the broadcast
+                * device is not hrtimer based. Otherwise we run into
+                * a hrtimer recursion.
+                *
+                * local timer_interrupt()
+                *   local_handler()
+                *     expire_hrtimers()
+                *       bc_handler()
+                *         local_handler()
+                *           expire_hrtimers()
+                */
+               local = !(bc->features & CLOCK_EVT_FEAT_HRTIMER);
        }
 
        if (!cpumask_empty(mask)) {
@@ -301,6 +316,13 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
        bool bc_local;
 
        raw_spin_lock(&tick_broadcast_lock);
+
+       /* Handle spurious interrupts gracefully */
+       if (clockevent_state_shutdown(tick_broadcast_device.evtdev)) {
+               raw_spin_unlock(&tick_broadcast_lock);
+               return;
+       }
+
        bc_local = tick_do_periodic_broadcast();
 
        if (clockevent_state_oneshot(dev)) {
@@ -359,8 +381,16 @@ void tick_broadcast_control(enum tick_broadcast_mode mode)
        case TICK_BROADCAST_ON:
                cpumask_set_cpu(cpu, tick_broadcast_on);
                if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
-                       if (tick_broadcast_device.mode ==
-                           TICKDEV_MODE_PERIODIC)
+                       /*
+                        * Only shutdown the cpu local device, if:
+                        *
+                        * - the broadcast device exists
+                        * - the broadcast device is not a hrtimer based one
+                        * - the broadcast device is in periodic mode to
+                        *   avoid a hickup during switch to oneshot mode
+                        */
+                       if (bc && !(bc->features & CLOCK_EVT_FEAT_HRTIMER) &&
+                           tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
                                clockevents_shutdown(dev);
                }
                break;
@@ -379,14 +409,16 @@ void tick_broadcast_control(enum tick_broadcast_mode mode)
                break;
        }
 
-       if (cpumask_empty(tick_broadcast_mask)) {
-               if (!bc_stopped)
-                       clockevents_shutdown(bc);
-       } else if (bc_stopped) {
-               if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
-                       tick_broadcast_start_periodic(bc);
-               else
-                       tick_broadcast_setup_oneshot(bc);
+       if (bc) {
+               if (cpumask_empty(tick_broadcast_mask)) {
+                       if (!bc_stopped)
+                               clockevents_shutdown(bc);
+               } else if (bc_stopped) {
+                       if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+                               tick_broadcast_start_periodic(bc);
+                       else
+                               tick_broadcast_setup_oneshot(bc);
+               }
        }
        raw_spin_unlock(&tick_broadcast_lock);
 }
@@ -662,71 +694,82 @@ static void broadcast_shutdown_local(struct clock_event_device *bc,
        clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
 }
 
-/**
- * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
- * @state:     The target state (enter/exit)
- *
- * The system enters/leaves a state, where affected devices might stop
- * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
- *
- * Called with interrupts disabled, so clockevents_lock is not
- * required here because the local clock event device cannot go away
- * under us.
- */
-int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
 {
        struct clock_event_device *bc, *dev;
-       struct tick_device *td;
        int cpu, ret = 0;
        ktime_t now;
 
        /*
-        * Periodic mode does not care about the enter/exit of power
-        * states
+        * If there is no broadcast device, tell the caller not to go
+        * into deep idle.
         */
-       if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
-               return 0;
+       if (!tick_broadcast_device.evtdev)
+               return -EBUSY;
 
-       /*
-        * We are called with preemtion disabled from the depth of the
-        * idle code, so we can't be moved away.
-        */
-       td = this_cpu_ptr(&tick_cpu_device);
-       dev = td->evtdev;
-
-       if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
-               return 0;
+       dev = this_cpu_ptr(&tick_cpu_device)->evtdev;
 
        raw_spin_lock(&tick_broadcast_lock);
        bc = tick_broadcast_device.evtdev;
        cpu = smp_processor_id();
 
        if (state == TICK_BROADCAST_ENTER) {
+               /*
+                * If the current CPU owns the hrtimer broadcast
+                * mechanism, it cannot go deep idle and we do not add
+                * the CPU to the broadcast mask. We don't have to go
+                * through the EXIT path as the local timer is not
+                * shutdown.
+                */
+               ret = broadcast_needs_cpu(bc, cpu);
+               if (ret)
+                       goto out;
+
+               /*
+                * If the broadcast device is in periodic mode, we
+                * return.
+                */
+               if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
+                       /* If it is a hrtimer based broadcast, return busy */
+                       if (bc->features & CLOCK_EVT_FEAT_HRTIMER)
+                               ret = -EBUSY;
+                       goto out;
+               }
+
                if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
                        WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
+
+                       /* Conditionally shut down the local timer. */
                        broadcast_shutdown_local(bc, dev);
+
                        /*
                         * We only reprogram the broadcast timer if we
                         * did not mark ourself in the force mask and
                         * if the cpu local event is earlier than the
                         * broadcast event. If the current CPU is in
                         * the force mask, then we are going to be
-                        * woken by the IPI right away.
+                        * woken by the IPI right away; we return
+                        * busy, so the CPU does not try to go deep
+                        * idle.
                         */
-                       if (!cpumask_test_cpu(cpu, tick_broadcast_force_mask) &&
-                           dev->next_event.tv64 < bc->next_event.tv64)
+                       if (cpumask_test_cpu(cpu, tick_broadcast_force_mask)) {
+                               ret = -EBUSY;
+                       } else if (dev->next_event.tv64 < bc->next_event.tv64) {
                                tick_broadcast_set_event(bc, cpu, dev->next_event);
+                               /*
+                                * In case of hrtimer broadcasts the
+                                * programming might have moved the
+                                * timer to this cpu. If yes, remove
+                                * us from the broadcast mask and
+                                * return busy.
+                                */
+                               ret = broadcast_needs_cpu(bc, cpu);
+                               if (ret) {
+                                       cpumask_clear_cpu(cpu,
+                                               tick_broadcast_oneshot_mask);
+                               }
+                       }
                }
-               /*
-                * If the current CPU owns the hrtimer broadcast
-                * mechanism, it cannot go deep idle and we remove the
-                * CPU from the broadcast mask. We don't have to go
-                * through the EXIT path as the local timer is not
-                * shutdown.
-                */
-               ret = broadcast_needs_cpu(bc, cpu);
-               if (ret)
-                       cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
        } else {
                if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
                        clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
@@ -796,7 +839,6 @@ out:
        raw_spin_unlock(&tick_broadcast_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(tick_broadcast_oneshot_control);
 
 /*
  * Reset the one shot broadcast for a cpu
@@ -938,6 +980,16 @@ bool tick_broadcast_oneshot_available(void)
        return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false;
 }
 
+#else
+int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+{
+       struct clock_event_device *bc = tick_broadcast_device.evtdev;
+
+       if (!bc || (bc->features & CLOCK_EVT_FEAT_HRTIMER))
+               return -EBUSY;
+
+       return 0;
+}
 #endif
 
 void __init tick_broadcast_init(void)
index 76446cb5dfe1a5280323f41c16299392e99efb93..f8bf47571dda4748f0d3be7574591566ccac8936 100644 (file)
@@ -343,6 +343,28 @@ out_bc:
        tick_install_broadcast_device(newdev);
 }
 
+/**
+ * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
+ * @state:     The target state (enter/exit)
+ *
+ * The system enters/leaves a state, where affected devices might stop
+ * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
+ *
+ * Called with interrupts disabled, so clockevents_lock is not
+ * required here because the local clock event device cannot go away
+ * under us.
+ */
+int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+{
+       struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
+
+       if (!(td->evtdev->features & CLOCK_EVT_FEAT_C3STOP))
+               return 0;
+
+       return __tick_broadcast_oneshot_control(state);
+}
+EXPORT_SYMBOL_GPL(tick_broadcast_oneshot_control);
+
 #ifdef CONFIG_HOTPLUG_CPU
 /*
  * Transfer the do_timer job away from a dying cpu.
index 42fdf4958bccd1c5d1593f4ebe578ea99477ddbf..a4a8d4e9baa13f37cbdceff5ffedc3bfc5fd8e4c 100644 (file)
@@ -71,4 +71,14 @@ extern void tick_cancel_sched_timer(int cpu);
 static inline void tick_cancel_sched_timer(int cpu) { }
 #endif
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+extern int __tick_broadcast_oneshot_control(enum tick_broadcast_state state);
+#else
+static inline int
+__tick_broadcast_oneshot_control(enum tick_broadcast_state state)
+{
+       return -EBUSY;
+}
+#endif
+
 #endif
index 5e097fa9faf7016470b8283931023a15d20ed97d..84190f02b521c9fc77cee6e6a6722000939ee470 100644 (file)
@@ -807,8 +807,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
                        spin_unlock(&base->lock);
                        base = new_base;
                        spin_lock(&base->lock);
-                       timer->flags &= ~TIMER_BASEMASK;
-                       timer->flags |= base->cpu;
+                       WRITE_ONCE(timer->flags,
+                                  (timer->flags & ~TIMER_BASEMASK) | base->cpu);
                }
        }
 
index 02bece4a99ea36bb835fc45a9aa55c1aedd69f9f..eb11011b5292add880af7038800560aa29c5a674 100644 (file)
@@ -98,6 +98,13 @@ struct ftrace_pid {
        struct pid *pid;
 };
 
+static bool ftrace_pids_enabled(void)
+{
+       return !list_empty(&ftrace_pids);
+}
+
+static void ftrace_update_trampoline(struct ftrace_ops *ops);
+
 /*
  * ftrace_disabled is set when an anomaly is discovered.
  * ftrace_disabled is much stronger than ftrace_enabled.
@@ -109,7 +116,6 @@ static DEFINE_MUTEX(ftrace_lock);
 static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end;
 static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;
 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;
-ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;
 static struct ftrace_ops global_ops;
 static struct ftrace_ops control_ops;
 
@@ -183,14 +189,7 @@ static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip,
        if (!test_tsk_trace_trace(current))
                return;
 
-       ftrace_pid_function(ip, parent_ip, op, regs);
-}
-
-static void set_ftrace_pid_function(ftrace_func_t func)
-{
-       /* do not set ftrace_pid_function to itself! */
-       if (func != ftrace_pid_func)
-               ftrace_pid_function = func;
+       op->saved_func(ip, parent_ip, op, regs);
 }
 
 /**
@@ -202,7 +201,6 @@ static void set_ftrace_pid_function(ftrace_func_t func)
 void clear_ftrace_function(void)
 {
        ftrace_trace_function = ftrace_stub;
-       ftrace_pid_function = ftrace_stub;
 }
 
 static void control_ops_disable_all(struct ftrace_ops *ops)
@@ -436,6 +434,12 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
        } else
                add_ftrace_ops(&ftrace_ops_list, ops);
 
+       /* Always save the function, and reset at unregistering */
+       ops->saved_func = ops->func;
+
+       if (ops->flags & FTRACE_OPS_FL_PID && ftrace_pids_enabled())
+               ops->func = ftrace_pid_func;
+
        ftrace_update_trampoline(ops);
 
        if (ftrace_enabled)
@@ -463,15 +467,28 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops)
        if (ftrace_enabled)
                update_ftrace_function();
 
+       ops->func = ops->saved_func;
+
        return 0;
 }
 
 static void ftrace_update_pid_func(void)
 {
+       bool enabled = ftrace_pids_enabled();
+       struct ftrace_ops *op;
+
        /* Only do something if we are tracing something */
        if (ftrace_trace_function == ftrace_stub)
                return;
 
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+               if (op->flags & FTRACE_OPS_FL_PID) {
+                       op->func = enabled ? ftrace_pid_func :
+                               op->saved_func;
+                       ftrace_update_trampoline(op);
+               }
+       } while_for_each_ftrace_op(op);
+
        update_ftrace_function();
 }
 
@@ -1133,7 +1150,8 @@ static struct ftrace_ops global_ops = {
        .local_hash.filter_hash         = EMPTY_HASH,
        INIT_OPS_HASH(global_ops)
        .flags                          = FTRACE_OPS_FL_RECURSION_SAFE |
-                                         FTRACE_OPS_FL_INITIALIZED,
+                                         FTRACE_OPS_FL_INITIALIZED |
+                                         FTRACE_OPS_FL_PID,
 };
 
 /*
@@ -5023,7 +5041,9 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)
 
 static struct ftrace_ops global_ops = {
        .func                   = ftrace_stub,
-       .flags                  = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
+       .flags                  = FTRACE_OPS_FL_RECURSION_SAFE |
+                                 FTRACE_OPS_FL_INITIALIZED |
+                                 FTRACE_OPS_FL_PID,
 };
 
 static int __init ftrace_nodyn_init(void)
@@ -5080,11 +5100,6 @@ void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func)
                if (WARN_ON(tr->ops->func != ftrace_stub))
                        printk("ftrace ops had %pS for function\n",
                               tr->ops->func);
-               /* Only the top level instance does pid tracing */
-               if (!list_empty(&ftrace_pids)) {
-                       set_ftrace_pid_function(func);
-                       func = ftrace_pid_func;
-               }
        }
        tr->ops->func = func;
        tr->ops->private = tr;
@@ -5371,7 +5386,7 @@ static void *fpid_start(struct seq_file *m, loff_t *pos)
 {
        mutex_lock(&ftrace_lock);
 
-       if (list_empty(&ftrace_pids) && (!*pos))
+       if (!ftrace_pids_enabled() && (!*pos))
                return (void *) 1;
 
        return seq_list_start(&ftrace_pids, *pos);
@@ -5610,6 +5625,7 @@ static struct ftrace_ops graph_ops = {
        .func                   = ftrace_stub,
        .flags                  = FTRACE_OPS_FL_RECURSION_SAFE |
                                   FTRACE_OPS_FL_INITIALIZED |
+                                  FTRACE_OPS_FL_PID |
                                   FTRACE_OPS_FL_STUB,
 #ifdef FTRACE_GRAPH_TRAMP_ADDR
        .trampoline             = FTRACE_GRAPH_TRAMP_ADDR,
index f060716b02ae25b45494b0f350df6fe2fc0f369b..74bde81601a902759e5714b04a5a987ddbde2d15 100644 (file)
@@ -444,6 +444,7 @@ enum {
 
        TRACE_CONTROL_BIT,
 
+       TRACE_BRANCH_BIT,
 /*
  * Abuse of the trace_recursion.
  * As we need a way to maintain state if we are tracing the function
index a87b43f49eb448afa3f1cc2bc44763d71f06dd52..e2e12ad3186f440f7841819a9f260509d5afde43 100644 (file)
@@ -36,9 +36,12 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
        struct trace_branch *entry;
        struct ring_buffer *buffer;
        unsigned long flags;
-       int cpu, pc;
+       int pc;
        const char *p;
 
+       if (current->trace_recursion & TRACE_BRANCH_BIT)
+               return;
+
        /*
         * I would love to save just the ftrace_likely_data pointer, but
         * this code can also be used by modules. Ugly things can happen
@@ -49,10 +52,10 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
        if (unlikely(!tr))
                return;
 
-       local_irq_save(flags);
-       cpu = raw_smp_processor_id();
-       data = per_cpu_ptr(tr->trace_buffer.data, cpu);
-       if (atomic_inc_return(&data->disabled) != 1)
+       raw_local_irq_save(flags);
+       current->trace_recursion |= TRACE_BRANCH_BIT;
+       data = this_cpu_ptr(tr->trace_buffer.data);
+       if (atomic_read(&data->disabled))
                goto out;
 
        pc = preempt_count();
@@ -81,8 +84,8 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
                __buffer_unlock_commit(buffer, event);
 
  out:
-       atomic_dec(&data->disabled);
-       local_irq_restore(flags);
+       current->trace_recursion &= ~TRACE_BRANCH_BIT;
+       raw_local_irq_restore(flags);
 }
 
 static inline
index 777eda7d1ab4bff70b8aa465e336465239c9f1b9..39f24d6721e5a29d8016811d4f5332fca66c2ec2 100644 (file)
@@ -18,10 +18,6 @@ config KASAN
          For better error detection enable CONFIG_STACKTRACE,
          and add slub_debug=U to boot cmdline.
 
-config KASAN_SHADOW_OFFSET
-       hex
-       default 0xdffffc0000000000 if X86_64
-
 choice
        prompt "Instrumentation type"
        depends on KASAN
index 528ff932d8e445ae9e19940d4f13cd20c0273bc7..62696dff5730be1927edfdafc7bc314e71226a88 100644 (file)
@@ -59,8 +59,11 @@ decompress_fn __init decompress_method(const unsigned char *inbuf, long len,
 {
        const struct compress_format *cf;
 
-       if (len < 2)
+       if (len < 2) {
+               if (name)
+                       *name = NULL;
                return NULL;    /* Need at least this much... */
+       }
 
        pr_debug("Compressed data magic: %#.2x %#.2x\n", inbuf[0], inbuf[1]);
 
index ae4b65e17e6486c7431fdc39335eab4cb15a0539..dace71fe41f707457468ec1ca3f8d94f756313a8 100644 (file)
@@ -574,6 +574,9 @@ void debug_dma_assert_idle(struct page *page)
        unsigned long flags;
        phys_addr_t cln;
 
+       if (dma_debug_disabled())
+               return;
+
        if (!page)
                return;
 
index 7ea09699855d98db901737bb6cfad30f4b32149f..8d74c20d8595c76d3882fcc02a7fa00f8db1bfaa 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/ctype.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <asm/unaligned.h>
 
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
@@ -139,7 +140,7 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
                for (j = 0; j < ngroups; j++) {
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%16.16llx", j ? " " : "",
-                                      (unsigned long long)*(ptr8 + j));
+                                      get_unaligned(ptr8 + j));
                        if (ret >= linebuflen - lx)
                                goto overflow1;
                        lx += ret;
@@ -150,7 +151,7 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
                for (j = 0; j < ngroups; j++) {
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%8.8x", j ? " " : "",
-                                      *(ptr4 + j));
+                                      get_unaligned(ptr4 + j));
                        if (ret >= linebuflen - lx)
                                goto overflow1;
                        lx += ret;
@@ -161,7 +162,7 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
                for (j = 0; j < ngroups; j++) {
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%4.4x", j ? " " : "",
-                                      *(ptr2 + j));
+                                      get_unaligned(ptr2 + j));
                        if (ret >= linebuflen - lx)
                                goto overflow1;
                        lx += ret;
index df30632f0bef9ec1c36a48d83a6eb87cd18ee405..ff19f66d3f7fbd635a44cc03614b5fbe4485cc56 100644 (file)
@@ -119,7 +119,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev,
        unsigned long align_mask = 0;
 
        if (align_order > 0)
-               align_mask = 0xffffffffffffffffl >> (64 - align_order);
+               align_mask = ~0ul >> (BITS_PER_LONG - align_order);
 
        /* Sanity check */
        if (unlikely(npages == 0)) {
index 2e3bd01964a9047f481862c2323be8c4ea42db9c..3e3a5c3cb330dfd39a5a24a0dc638c5f4ecdbfe0 100644 (file)
@@ -337,8 +337,9 @@ error:
 }
 EXPORT_SYMBOL(kobject_init);
 
-static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
-                           const char *fmt, va_list vargs)
+static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
+                                          struct kobject *parent,
+                                          const char *fmt, va_list vargs)
 {
        int retval;
 
index a60a6d335a91a6aa90f019f77062e7be069939fd..cc0c69710dcf8a2c7474b759be72e8fa22c2ca1f 100644 (file)
@@ -610,6 +610,8 @@ next:
                iter->skip = 0;
        }
 
+       iter->p = NULL;
+
        /* Ensure we see any new tables. */
        smp_rmb();
 
@@ -620,8 +622,6 @@ next:
                return ERR_PTR(-EAGAIN);
        }
 
-       iter->p = NULL;
-
        return NULL;
 }
 EXPORT_SYMBOL_GPL(rhashtable_walk_next);
index 1132d733556dbc330d32eda5460f55e6e067b627..17c75a4246c8bbab8b56fe4d562cd85ea670a21f 100644 (file)
--- a/mm/cma.h
+++ b/mm/cma.h
@@ -16,7 +16,7 @@ struct cma {
 extern struct cma cma_areas[MAX_CMA_AREAS];
 extern unsigned cma_area_count;
 
-static unsigned long cma_bitmap_maxno(struct cma *cma)
+static inline unsigned long cma_bitmap_maxno(struct cma *cma)
 {
        return cma->count >> cma->order_per_bit;
 }
index 7621ee34daa0dea1dd0246238e7eb5bc613cfe4c..f8e4b60db167215862824637d856ffb34332f071 100644 (file)
@@ -39,7 +39,7 @@ static int cma_used_get(void *data, u64 *val)
 
        mutex_lock(&cma->lock);
        /* pages counter is smaller than sizeof(int) */
-       used = bitmap_weight(cma->bitmap, (int)cma->count);
+       used = bitmap_weight(cma->bitmap, (int)cma_bitmap_maxno(cma));
        mutex_unlock(&cma->lock);
        *val = (u64)used << cma->order_per_bit;
 
@@ -52,13 +52,14 @@ static int cma_maxchunk_get(void *data, u64 *val)
        struct cma *cma = data;
        unsigned long maxchunk = 0;
        unsigned long start, end = 0;
+       unsigned long bitmap_maxno = cma_bitmap_maxno(cma);
 
        mutex_lock(&cma->lock);
        for (;;) {
-               start = find_next_zero_bit(cma->bitmap, cma->count, end);
+               start = find_next_zero_bit(cma->bitmap, bitmap_maxno, end);
                if (start >= cma->count)
                        break;
-               end = find_next_bit(cma->bitmap, cma->count, start);
+               end = find_next_bit(cma->bitmap, bitmap_maxno, start);
                maxchunk = max(end - start, maxchunk);
        }
        mutex_unlock(&cma->lock);
@@ -170,10 +171,10 @@ static void cma_debugfs_add_one(struct cma *cma, int idx)
 
        tmp = debugfs_create_dir(name, cma_debugfs_root);
 
-       debugfs_create_file("alloc", S_IWUSR, cma_debugfs_root, cma,
+       debugfs_create_file("alloc", S_IWUSR, tmp, cma,
                                &cma_alloc_fops);
 
-       debugfs_create_file("free", S_IWUSR, cma_debugfs_root, cma,
+       debugfs_create_file("free", S_IWUSR, tmp, cma,
                                &cma_free_fops);
 
        debugfs_create_file("base_pfn", S_IRUGO, tmp,
index c107094f79bae9ee895bd6bf30976d900f16c141..097c7a4bfbd9f13f4845acae80d73aa7b0e66fb2 100644 (file)
@@ -1676,12 +1676,7 @@ static void __split_huge_page_refcount(struct page *page,
                /* after clearing PageTail the gup refcount can be released */
                smp_mb__after_atomic();
 
-               /*
-                * retain hwpoison flag of the poisoned tail page:
-                *   fix for the unsuitable process killed on Guest Machine(KVM)
-                *   by the memory-failure.
-                */
-               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
+               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
                page_tail->flags |= (page->flags &
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
index 6c513a63ea84c3c7ffd41201b7a419ff7b6dfd5d..7b28e9cdf1c7686428fe49802fced44088043555 100644 (file)
@@ -2,7 +2,7 @@
  * This file contains shadow memory manipulation code.
  *
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
  *
  * Some of code borrowed from https://github.com/xairy/linux by
  *        Andrey Konovalov <adech.fo@gmail.com>
index 680ceedf810ab4c9cd08c9929f5d445de9f5aa6a..e07c94fbd0ac5a141ecf95ab7d39d046fea13e67 100644 (file)
@@ -2,7 +2,7 @@
  * This file contains error reporting code.
  *
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
  *
  * Some of code borrowed from https://github.com/xairy/linux by
  *        Andrey Konovalov <adech.fo@gmail.com>
index c53543d892828e75796239d6ce36afa90203085b..1f4446a90cef07c67ee1082b83f0ca87ebfefea1 100644 (file)
@@ -909,6 +909,18 @@ int get_hwpoison_page(struct page *page)
         * directly for tail pages.
         */
        if (PageTransHuge(head)) {
+               /*
+                * Non anonymous thp exists only in allocation/free time. We
+                * can't handle such a case correctly, so let's give it up.
+                * This should be better than triggering BUG_ON when kernel
+                * tries to touch the "partially handled" page.
+                */
+               if (!PageAnon(head)) {
+                       pr_err("MCE: %#lx: non anonymous thp\n",
+                               page_to_pfn(page));
+                       return 0;
+               }
+
                if (get_page_unless_zero(head)) {
                        if (PageTail(page))
                                get_page(page);
@@ -1134,17 +1146,11 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        }
 
        if (!PageHuge(p) && PageTransHuge(hpage)) {
-               if (!PageAnon(hpage)) {
-                       pr_err("MCE: %#lx: non anonymous thp\n", pfn);
-                       if (TestClearPageHWPoison(p))
-                               atomic_long_sub(nr_pages, &num_poisoned_pages);
-                       put_page(p);
-                       if (p != hpage)
-                               put_page(hpage);
-                       return -EBUSY;
-               }
-               if (unlikely(split_huge_page(hpage))) {
-                       pr_err("MCE: %#lx: thp split failed\n", pfn);
+               if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+                       if (!PageAnon(hpage))
+                               pr_err("MCE: %#lx: non anonymous thp\n", pfn);
+                       else
+                               pr_err("MCE: %#lx: thp split failed\n", pfn);
                        if (TestClearPageHWPoison(p))
                                atomic_long_sub(nr_pages, &num_poisoned_pages);
                        put_page(p);
@@ -1209,9 +1215,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        if (!PageHWPoison(p)) {
                printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn);
                atomic_long_sub(nr_pages, &num_poisoned_pages);
+               unlock_page(hpage);
                put_page(hpage);
-               res = 0;
-               goto out;
+               return 0;
        }
        if (hwpoison_filter(p)) {
                if (TestClearPageHWPoison(p))
@@ -1535,6 +1541,8 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags)
                 */
                ret = __get_any_page(page, pfn, 0);
                if (!PageLRU(page)) {
+                       /* Drop page reference which is from __get_any_page() */
+                       put_page(page);
                        pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n",
                                pfn, page->flags);
                        return -EIO;
@@ -1564,13 +1572,12 @@ static int soft_offline_huge_page(struct page *page, int flags)
        unlock_page(hpage);
 
        ret = isolate_huge_page(hpage, &pagelist);
-       if (ret) {
-               /*
-                * get_any_page() and isolate_huge_page() takes a refcount each,
-                * so need to drop one here.
-                */
-               put_page(hpage);
-       } else {
+       /*
+        * get_any_page() and isolate_huge_page() takes a refcount each,
+        * so need to drop one here.
+        */
+       put_page(hpage);
+       if (!ret) {
                pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn);
                return -EBUSY;
        }
@@ -1656,6 +1663,8 @@ static int __soft_offline_page(struct page *page, int flags)
                inc_zone_page_state(page, NR_ISOLATED_ANON +
                                        page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
+               if (!TestSetPageHWPoison(page))
+                       atomic_long_inc(&num_poisoned_pages);
                ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL,
                                        MIGRATE_SYNC, MR_MEMORY_FAILURE);
                if (ret) {
@@ -1670,9 +1679,8 @@ static int __soft_offline_page(struct page *page, int flags)
                                pfn, ret, page->flags);
                        if (ret > 0)
                                ret = -EIO;
-               } else {
-                       SetPageHWPoison(page);
-                       atomic_long_inc(&num_poisoned_pages);
+                       if (TestClearPageHWPoison(page))
+                               atomic_long_dec(&num_poisoned_pages);
                }
        } else {
                pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n",
index a84fbb772034f2e73eac300e254bd54f2a36ce03..388dcf9aa283c83ee78dcf22503de253e812a27d 100644 (file)
@@ -2670,6 +2670,10 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
 
        pte_unmap(page_table);
 
+       /* File mapping without ->vm_ops ? */
+       if (vma->vm_flags & VM_SHARED)
+               return VM_FAULT_SIGBUS;
+
        /* Check if we need to add a guard page to the stack */
        if (check_stack_guard_page(vma, address) < 0)
                return VM_FAULT_SIGSEGV;
@@ -3099,6 +3103,9 @@ static int do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
 
        pte_unmap(page_table);
+       /* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */
+       if (!vma->vm_ops->fault)
+               return VM_FAULT_SIGBUS;
        if (!(flags & FAULT_FLAG_WRITE))
                return do_read_fault(mm, vma, address, pmd, pgoff, flags,
                                orig_pte);
@@ -3244,13 +3251,12 @@ static int handle_pte_fault(struct mm_struct *mm,
        barrier();
        if (!pte_present(entry)) {
                if (pte_none(entry)) {
-                       if (vma->vm_ops) {
-                               if (likely(vma->vm_ops->fault))
-                                       return do_fault(mm, vma, address, pte,
-                                                       pmd, flags, entry);
-                       }
-                       return do_anonymous_page(mm, vma, address,
-                                                pte, pmd, flags);
+                       if (vma->vm_ops)
+                               return do_fault(mm, vma, address, pte, pmd,
+                                               flags, entry);
+
+                       return do_anonymous_page(mm, vma, address, pte, pmd,
+                                       flags);
                }
                return do_swap_page(mm, vma, address,
                                        pte, pmd, flags, entry);
index 26fbba7d888f887c3383c1bb5829cb4f204e2040..6da82bcb0a8b66b7326c1a021a7eac3b476cd85e 100644 (file)
@@ -446,7 +446,7 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        int nr_pages = PAGES_PER_SECTION;
        int nid = pgdat->node_id;
        int zone_type;
-       unsigned long flags;
+       unsigned long flags, pfn;
        int ret;
 
        zone_type = zone - pgdat->node_zones;
@@ -461,6 +461,14 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        pgdat_resize_unlock(zone->zone_pgdat, &flags);
        memmap_init_zone(nr_pages, nid, zone_type,
                         phys_start_pfn, MEMMAP_HOTPLUG);
+
+       /* online_page_range is called later and expects pages reserved */
+       for (pfn = phys_start_pfn; pfn < phys_start_pfn + nr_pages; pfn++) {
+               if (!pfn_valid(pfn))
+                       continue;
+
+               SetPageReserved(pfn_to_page(pfn));
+       }
        return 0;
 }
 
@@ -1269,6 +1277,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
 
        /* create new memmap entry */
        firmware_map_add_hotplug(start, start + size, "System RAM");
+       memblock_add_node(start, size, nid);
 
        goto out;
 
@@ -2005,6 +2014,8 @@ void __ref remove_memory(int nid, u64 start, u64 size)
 
        /* remove memmap entry */
        firmware_map_remove(start, start + size, "System RAM");
+       memblock_free(start, size);
+       memblock_remove(start, size);
 
        arch_remove_memory(start, size);
 
index ee401e4e5ef187c92247d03dd6d2ea0893092d1c..eb4267107d1fee9fa2a55e4076c014500e3b1edb 100644 (file)
@@ -880,7 +880,8 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        /* Establish migration ptes or remove ptes */
        if (page_mapped(page)) {
                try_to_unmap(page,
-                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
+                       TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS|
+                       TTU_IGNORE_HWPOISON);
                page_was_mapped = 1;
        }
 
@@ -950,7 +951,10 @@ out:
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
-               if (reason != MR_MEMORY_FAILURE)
+               /* Soft-offlined page shouldn't go through lru cache list */
+               if (reason == MR_MEMORY_FAILURE)
+                       put_page(page);
+               else
                        putback_lru_page(page);
        }
 
index 22cddd3e5de8433952e99438d3260ae9ff20bd8d..5cccc127ef81f1d64ca46f9ce9ad50f519d4ea9f 100644 (file)
@@ -2063,10 +2063,10 @@ static struct notifier_block ratelimit_nb = {
  */
 void __init page_writeback_init(void)
 {
+       BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
+
        writeback_set_ratelimit();
        register_cpu_notifier(&ratelimit_nb);
-
-       BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL));
 }
 
 /**
index 506eac8b38afb2cdbeb481dcebad098aac984618..5b5240b7f642de179efa3552245fbf9326d7a206 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/interrupt.h>
-#include <linux/rwsem.h>
 #include <linux/pagemap.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
@@ -246,9 +245,7 @@ static inline void reset_deferred_meminit(pg_data_t *pgdat)
 /* Returns true if the struct page for the pfn is uninitialised */
 static inline bool __meminit early_page_uninitialised(unsigned long pfn)
 {
-       int nid = early_pfn_to_nid(pfn);
-
-       if (pfn >= NODE_DATA(nid)->first_deferred_pfn)
+       if (pfn >= NODE_DATA(early_pfn_to_nid(pfn))->first_deferred_pfn)
                return true;
 
        return false;
@@ -983,21 +980,21 @@ static void __init __free_pages_boot_core(struct page *page,
 
 #if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \
        defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP)
-/* Only safe to use early in boot when initialisation is single-threaded */
+
 static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata;
 
 int __meminit early_pfn_to_nid(unsigned long pfn)
 {
+       static DEFINE_SPINLOCK(early_pfn_lock);
        int nid;
 
-       /* The system will behave unpredictably otherwise */
-       BUG_ON(system_state != SYSTEM_BOOTING);
-
+       spin_lock(&early_pfn_lock);
        nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache);
-       if (nid >= 0)
-               return nid;
-       /* just returns 0 */
-       return 0;
+       if (nid < 0)
+               nid = 0;
+       spin_unlock(&early_pfn_lock);
+
+       return nid;
 }
 #endif
 
@@ -1062,7 +1059,15 @@ static void __init deferred_free_range(struct page *page,
                __free_pages_boot_core(page, pfn, 0);
 }
 
-static __initdata DECLARE_RWSEM(pgdat_init_rwsem);
+/* Completion tracking for deferred_init_memmap() threads */
+static atomic_t pgdat_init_n_undone __initdata;
+static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp);
+
+static inline void __init pgdat_init_report_one_done(void)
+{
+       if (atomic_dec_and_test(&pgdat_init_n_undone))
+               complete(&pgdat_init_all_done_comp);
+}
 
 /* Initialise remaining memory on a node */
 static int __init deferred_init_memmap(void *data)
@@ -1079,7 +1084,7 @@ static int __init deferred_init_memmap(void *data)
        const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
 
        if (first_init_pfn == ULONG_MAX) {
-               up_read(&pgdat_init_rwsem);
+               pgdat_init_report_one_done();
                return 0;
        }
 
@@ -1179,7 +1184,8 @@ free_range:
 
        pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
                                        jiffies_to_msecs(jiffies - start));
-       up_read(&pgdat_init_rwsem);
+
+       pgdat_init_report_one_done();
        return 0;
 }
 
@@ -1187,14 +1193,17 @@ void __init page_alloc_init_late(void)
 {
        int nid;
 
+       /* There will be num_node_state(N_MEMORY) threads */
+       atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY));
        for_each_node_state(nid, N_MEMORY) {
-               down_read(&pgdat_init_rwsem);
                kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
        }
 
        /* Block until all are initialised */
-       down_write(&pgdat_init_rwsem);
-       up_write(&pgdat_init_rwsem);
+       wait_for_completion(&pgdat_init_all_done_comp);
+
+       /* Reinit limits that are based on free pages after the kernel is up */
+       files_maxfiles_init();
 }
 #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 
@@ -1287,6 +1296,10 @@ static inline int check_new_page(struct page *page)
                bad_reason = "non-NULL mapping";
        if (unlikely(atomic_read(&page->_count) != 0))
                bad_reason = "nonzero _count";
+       if (unlikely(page->flags & __PG_HWPOISON)) {
+               bad_reason = "HWPoisoned (hardware-corrupted)";
+               bad_flags = __PG_HWPOISON;
+       }
        if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) {
                bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
                bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
@@ -1330,12 +1343,15 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
        set_page_owner(page, order, gfp_flags);
 
        /*
-        * page->pfmemalloc is set when ALLOC_NO_WATERMARKS was necessary to
+        * page is set pfmemalloc when ALLOC_NO_WATERMARKS was necessary to
         * allocate the page. The expectation is that the caller is taking
         * steps that will free more memory. The caller should avoid the page
         * being used for !PFMEMALLOC purposes.
         */
-       page->pfmemalloc = !!(alloc_flags & ALLOC_NO_WATERMARKS);
+       if (alloc_flags & ALLOC_NO_WATERMARKS)
+               set_page_pfmemalloc(page);
+       else
+               clear_page_pfmemalloc(page);
 
        return 0;
 }
@@ -1950,6 +1966,7 @@ void free_hot_cold_page_list(struct list_head *list, bool cold)
 void split_page(struct page *page, unsigned int order)
 {
        int i;
+       gfp_t gfp_mask;
 
        VM_BUG_ON_PAGE(PageCompound(page), page);
        VM_BUG_ON_PAGE(!page_count(page), page);
@@ -1963,10 +1980,11 @@ void split_page(struct page *page, unsigned int order)
                split_page(virt_to_page(page[0].shadow), order);
 #endif
 
-       set_page_owner(page, 0, 0);
+       gfp_mask = get_page_owner_gfp(page);
+       set_page_owner(page, 0, gfp_mask);
        for (i = 1; i < (1 << order); i++) {
                set_page_refcounted(page + i);
-               set_page_owner(page + i, 0, 0);
+               set_page_owner(page + i, 0, gfp_mask);
        }
 }
 EXPORT_SYMBOL_GPL(split_page);
@@ -1996,6 +2014,8 @@ int __isolate_free_page(struct page *page, unsigned int order)
        zone->free_area[order].nr_free--;
        rmv_page_order(page);
 
+       set_page_owner(page, order, __GFP_MOVABLE);
+
        /* Set the pageblock if the isolated page is at least a pageblock */
        if (order >= pageblock_order - 1) {
                struct page *endpage = page + (1 << order) - 1;
@@ -2007,7 +2027,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
                }
        }
 
-       set_page_owner(page, order, 0);
+
        return 1UL << order;
 }
 
@@ -3328,7 +3348,7 @@ refill:
                atomic_add(size - 1, &page->_count);
 
                /* reset page count bias and offset to start of new frag */
-               nc->pfmemalloc = page->pfmemalloc;
+               nc->pfmemalloc = page_is_pfmemalloc(page);
                nc->pagecnt_bias = size;
                nc->offset = size;
        }
@@ -5043,6 +5063,10 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid,
 {
        unsigned long zone_start_pfn, zone_end_pfn;
 
+       /* When hotadd a new node, the node should be empty */
+       if (!node_start_pfn && !node_end_pfn)
+               return 0;
+
        /* Get the start and end of the zone */
        zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
        zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
@@ -5106,6 +5130,10 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid,
        unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
        unsigned long zone_start_pfn, zone_end_pfn;
 
+       /* When hotadd a new node, the node should be empty */
+       if (!node_start_pfn && !node_end_pfn)
+               return 0;
+
        zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
        zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high);
 
index bd5f842b56d26aca3cf24225884d5a2eacd1580c..983c3a10fa07058df249c64d5c89b9578661f672 100644 (file)
@@ -76,6 +76,13 @@ void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
        __set_bit(PAGE_EXT_OWNER, &page_ext->flags);
 }
 
+gfp_t __get_page_owner_gfp(struct page *page)
+{
+       struct page_ext *page_ext = lookup_page_ext(page);
+
+       return page_ext->gfp_mask;
+}
+
 static ssize_t
 print_page_owner(char __user *buf, size_t count, unsigned long pfn,
                struct page *page, struct page_ext *page_ext)
index 4caf8ed24d6586e32ab910f28f945c01cef6373b..dbe0c1e8349c72ac569a58289da702a841104951 100644 (file)
@@ -3363,8 +3363,8 @@ put_path:
  * shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be
  *     kernel internal.  There will be NO LSM permission checks against the
  *     underlying inode.  So users of this interface must do LSM checks at a
- *     higher layer.  The one user is the big_key implementation.  LSM checks
- *     are provided at the key level rather than the inode level.
+ *     higher layer.  The users are the big_key and shm implementations.  LSM
+ *     checks are provided at the key or shm level rather than the inode.
  * @name: name for dentry (to be seen in /proc/<pid>/maps
  * @size: size to be set for the file
  * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
index 200e22412a161fc7a2232bcb923f07bc117362b8..bbd0b47dc6a97eecea7650ce6b351e88d5a17295 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1603,7 +1603,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
        }
 
        /* Record if ALLOC_NO_WATERMARKS was set when allocating the slab */
-       if (unlikely(page->pfmemalloc))
+       if (page_is_pfmemalloc(page))
                pfmemalloc_active = true;
 
        nr_pages = (1 << cachep->gfporder);
@@ -1614,7 +1614,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags,
                add_zone_page_state(page_zone(page),
                        NR_SLAB_UNRECLAIMABLE, nr_pages);
        __SetPageSlab(page);
-       if (page->pfmemalloc)
+       if (page_is_pfmemalloc(page))
                SetPageSlabPfmemalloc(page);
 
        if (kmemcheck_enabled && !(cachep->flags & SLAB_NOTRACK)) {
index 3e5f8f29c28640e44af5f5f9d1c3553986064588..86831105a09f44ffae37c074a6e5587c5b7056ce 100644 (file)
@@ -37,8 +37,7 @@ struct kmem_cache *kmem_cache;
                SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \
                SLAB_FAILSLAB)
 
-#define SLAB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
-               SLAB_CACHE_DMA | SLAB_NOTRACK)
+#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | SLAB_NOTRACK)
 
 /*
  * Merge control. If this is set then no merging of slab caches will occur.
index 816df0016555ad8a5cf03c8020e0b39b75b0a498..f68c0e50f3c083abe295a1dcd60668321a8f9232 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1427,7 +1427,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        inc_slabs_node(s, page_to_nid(page), page->objects);
        page->slab_cache = s;
        __SetPageSlab(page);
-       if (page->pfmemalloc)
+       if (page_is_pfmemalloc(page))
                SetPageSlabPfmemalloc(page);
 
        start = page_address(page);
index e61445dce04e3cc83e9704e84f3d5bf9074b31db..8286938c70ded6b82d4268174c92669a90eeb674 100644 (file)
@@ -973,22 +973,18 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                 *    caller can stall after page list has been processed.
                 *
                 * 2) Global or new memcg reclaim encounters a page that is
-                *    not marked for immediate reclaim or the caller does not
-                *    have __GFP_IO. In this case mark the page for immediate
+                *    not marked for immediate reclaim, or the caller does not
+                *    have __GFP_FS (or __GFP_IO if it's simply going to swap,
+                *    not to fs). In this case mark the page for immediate
                 *    reclaim and continue scanning.
                 *
-                *    __GFP_IO is checked  because a loop driver thread might
+                *    Require may_enter_fs because we would wait on fs, which
+                *    may not have submitted IO yet. And the loop driver might
                 *    enter reclaim, and deadlock if it waits on a page for
                 *    which it is needed to do the write (loop masks off
                 *    __GFP_IO|__GFP_FS for this reason); but more thought
                 *    would probably show more reasons.
                 *
-                *    Don't require __GFP_FS, since we're not going into the
-                *    FS, just waiting on its writeback completion. Worryingly,
-                *    ext4 gfs2 and xfs allocate pages with
-                *    grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing
-                *    may_enter_fs here is liable to OOM on them.
-                *
                 * 3) Legacy memcg encounters a page that is not already marked
                 *    PageReclaim. memcg does not have any dirty pages
                 *    throttling so we could easily OOM just because too many
@@ -1005,7 +1001,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
 
                        /* Case 2 above */
                        } else if (sane_reclaim(sc) ||
-                           !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) {
+                           !PageReclaim(page) || !may_enter_fs) {
                                /*
                                 * This is slightly racy - end_page_writeback()
                                 * might have just cleared PageReclaim, then
index 498454b3c06c3ddf0e8c3989e23bef9360587544..ea79ee9a73489f43a88e57c2eb529fc11d894e5f 100644 (file)
@@ -1541,6 +1541,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
        struct p9_client *clnt = fid->clnt;
        struct p9_req_t *req;
        int total = 0;
+       *err = 0;
 
        p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
                   fid->fid, (unsigned long long) offset, (int)iov_iter_count(to));
@@ -1620,6 +1621,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
        struct p9_client *clnt = fid->clnt;
        struct p9_req_t *req;
        int total = 0;
+       *err = 0;
 
        p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n",
                                fid->fid, (unsigned long long) offset,
index 9dd49ca67dbc22a905999de21b8355475ba40052..6e70ddb158b4bc121a0f32e7a53fecf8125e8354 100644 (file)
@@ -704,6 +704,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
 
        mutex_unlock(&virtio_9p_lock);
 
+       vdev->config->reset(vdev);
        vdev->config->del_vqs(vdev);
 
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
index 1997538a5d23d93ddca9724fd3787dc0b0b2595a..3b78e8473a01b4a82e376266b04078e714ce1e26 100644 (file)
@@ -264,6 +264,7 @@ void ax25_disconnect(ax25_cb *ax25, int reason)
 {
        ax25_clear_queues(ax25);
 
+       ax25_stop_heartbeat(ax25);
        ax25_stop_t1timer(ax25);
        ax25_stop_t2timer(ax25);
        ax25_stop_t3timer(ax25);
index fb54e6aed096edd267fc211e4cd2a0139fe71f8a..6d0b471eede8639f55b33c5c4d434c8fddef6ee5 100644 (file)
@@ -1138,6 +1138,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: packet to check
  * @hdr_size: size of the encapsulation header
+ *
+ * Returns true if the packet was snooped and consumed by DAT. False if the
+ * packet has to be delivered to the interface
  */
 bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
                                         struct sk_buff *skb, int hdr_size)
@@ -1145,7 +1148,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
        uint16_t type;
        __be32 ip_src, ip_dst;
        uint8_t *hw_src, *hw_dst;
-       bool ret = false;
+       bool dropped = false;
        unsigned short vid;
 
        if (!atomic_read(&bat_priv->distributed_arp_table))
@@ -1174,12 +1177,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
        /* if this REPLY is directed to a client of mine, let's deliver the
         * packet to the interface
         */
-       ret = !batadv_is_my_client(bat_priv, hw_dst, vid);
+       dropped = !batadv_is_my_client(bat_priv, hw_dst, vid);
+
+       /* if this REPLY is sent on behalf of a client of mine, let's drop the
+        * packet because the client will reply by itself
+        */
+       dropped |= batadv_is_my_client(bat_priv, hw_src, vid);
 out:
-       if (ret)
+       if (dropped)
                kfree_skb(skb);
-       /* if ret == false -> packet has to be delivered to the interface */
-       return ret;
+       /* if dropped == false -> deliver to the interface */
+       return dropped;
 }
 
 /**
index bb01586206289929f8c5e43153b75f9c279b9f85..cffa92dd98778bf2ffdf11107243fcc0f60cab6b 100644 (file)
@@ -439,6 +439,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 
        INIT_HLIST_NODE(&gw_node->list);
        gw_node->orig_node = orig_node;
+       gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
+       gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
        atomic_set(&gw_node->refcount, 1);
 
        spin_lock_bh(&bat_priv->gw.list_lock);
index c002961da75d655deb813990f5706cf37fbd6d7d..a2fc843c22432e790980fa15653cf95e6c60b384 100644 (file)
@@ -479,6 +479,9 @@ out:
  */
 void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
 {
+       if (!vlan)
+               return;
+
        if (atomic_dec_and_test(&vlan->refcount)) {
                spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
                hlist_del_rcu(&vlan->list);
index b4824951010ba6b42bf7d7c7eb62c529ed340158..5809b39c1922320e8dbb353de212b472199c796d 100644 (file)
@@ -594,6 +594,12 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 
        /* increase the refcounter of the related vlan */
        vlan = batadv_softif_vlan_get(bat_priv, vid);
+       if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d",
+                addr, BATADV_PRINT_VID(vid))) {
+               kfree(tt_local);
+               tt_local = NULL;
+               goto out;
+       }
 
        batadv_dbg(BATADV_DBG_TT, bat_priv,
                   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
@@ -1034,6 +1040,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
        struct batadv_tt_local_entry *tt_local_entry;
        uint16_t flags, curr_flags = BATADV_NO_FLAGS;
        struct batadv_softif_vlan *vlan;
+       void *tt_entry_exists;
 
        tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
        if (!tt_local_entry)
@@ -1061,11 +1068,22 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
         * immediately purge it
         */
        batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
-       hlist_del_rcu(&tt_local_entry->common.hash_entry);
+
+       tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash,
+                                            batadv_compare_tt,
+                                            batadv_choose_tt,
+                                            &tt_local_entry->common);
+       if (!tt_entry_exists)
+               goto out;
+
+       /* extra call to free the local tt entry */
        batadv_tt_local_entry_free_ref(tt_local_entry);
 
        /* decrease the reference held for this vlan */
        vlan = batadv_softif_vlan_get(bat_priv, vid);
+       if (!vlan)
+               goto out;
+
        batadv_softif_vlan_free_ref(vlan);
        batadv_softif_vlan_free_ref(vlan);
 
@@ -1166,8 +1184,10 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
                        /* decrease the reference held for this vlan */
                        vlan = batadv_softif_vlan_get(bat_priv,
                                                      tt_common_entry->vid);
-                       batadv_softif_vlan_free_ref(vlan);
-                       batadv_softif_vlan_free_ref(vlan);
+                       if (vlan) {
+                               batadv_softif_vlan_free_ref(vlan);
+                               batadv_softif_vlan_free_ref(vlan);
+                       }
 
                        batadv_tt_local_entry_free_ref(tt_local);
                }
@@ -3207,8 +3227,10 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
 
                        /* decrease the reference held for this vlan */
                        vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
-                       batadv_softif_vlan_free_ref(vlan);
-                       batadv_softif_vlan_free_ref(vlan);
+                       if (vlan) {
+                               batadv_softif_vlan_free_ref(vlan);
+                               batadv_softif_vlan_free_ref(vlan);
+                       }
 
                        batadv_tt_local_entry_free_ref(tt_local);
                }
index 7998fb27916568da087b2734a017355158044a75..92720f3fe57370137f22ae3d2b76b390da09e9a1 100644 (file)
@@ -7820,7 +7820,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
        /* Make sure we copy only the significant bytes based on the
         * encryption key size, and set the rest of the value to zeroes.
         */
-       memcpy(ev.key.val, key->val, sizeof(key->enc_size));
+       memcpy(ev.key.val, key->val, key->enc_size);
        memset(ev.key.val + key->enc_size, 0,
               sizeof(ev.key.val) - key->enc_size);
 
index 3d0f7d2a06162248a1e6589fe3d59022f9dded0d..ad82324f710f0f97427a51c632e5a8aebfaba292 100644 (file)
@@ -2312,6 +2312,10 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
                return 1;
 
        chan = conn->smp;
+       if (!chan) {
+               BT_ERR("SMP security requested but not available");
+               return 1;
+       }
 
        if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED))
                return 1;
index e97572b5d2ccfbce420009f60b30f5439fd1c571..fa7bfced888ec0f3b7d8a5ceff17b597cbe9b79e 100644 (file)
@@ -37,14 +37,30 @@ static inline int should_deliver(const struct net_bridge_port *p,
 
 int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb)
 {
-       if (!is_skb_forwardable(skb->dev, skb)) {
-               kfree_skb(skb);
-       } else {
-               skb_push(skb, ETH_HLEN);
-               br_drop_fake_rtable(skb);
-               dev_queue_xmit(skb);
+       if (!is_skb_forwardable(skb->dev, skb))
+               goto drop;
+
+       skb_push(skb, ETH_HLEN);
+       br_drop_fake_rtable(skb);
+       skb_sender_cpu_clear(skb);
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL &&
+           (skb->protocol == htons(ETH_P_8021Q) ||
+            skb->protocol == htons(ETH_P_8021AD))) {
+               int depth;
+
+               if (!__vlan_get_protocol(skb, skb->protocol, &depth))
+                       goto drop;
+
+               skb_set_network_header(skb, depth);
        }
 
+       dev_queue_xmit(skb);
+
+       return 0;
+
+drop:
+       kfree_skb(skb);
        return 0;
 }
 EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
index e29ad70b3000be4f0e7486b172746ea62b4f216f..c94321955db711fdc964930c51a69d1290d39490 100644 (file)
@@ -323,6 +323,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
        struct net_bridge_port_group *p;
        struct net_bridge_port_group __rcu **pp;
        struct net_bridge_mdb_htable *mdb;
+       unsigned long now = jiffies;
        int err;
 
        mdb = mlock_dereference(br->mdb, br);
@@ -347,8 +348,9 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
        if (unlikely(!p))
                return -ENOMEM;
        rcu_assign_pointer(*pp, p);
+       if (state == MDB_TEMPORARY)
+               mod_timer(&p->timer, now + br->multicast_membership_interval);
 
-       br_mdb_notify(br->dev, port, group, RTM_NEWMDB);
        return 0;
 }
 
@@ -371,6 +373,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
        if (!p || p->br != br || p->state == BR_STATE_DISABLED)
                return -EINVAL;
 
+       memset(&ip, 0, sizeof(ip));
        ip.proto = entry->addr.proto;
        if (ip.proto == htons(ETH_P_IP))
                ip.u.ip4 = entry->addr.u.ip4;
@@ -417,20 +420,14 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
        if (!netif_running(br->dev) || br->multicast_disabled)
                return -EINVAL;
 
+       memset(&ip, 0, sizeof(ip));
        ip.proto = entry->addr.proto;
-       if (ip.proto == htons(ETH_P_IP)) {
-               if (timer_pending(&br->ip4_other_query.timer))
-                       return -EBUSY;
-
+       if (ip.proto == htons(ETH_P_IP))
                ip.u.ip4 = entry->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
-       } else {
-               if (timer_pending(&br->ip6_other_query.timer))
-                       return -EBUSY;
-
+       else
                ip.u.ip6 = entry->addr.u.ip6;
 #endif
-       }
 
        spin_lock_bh(&br->multicast_lock);
        mdb = mlock_dereference(br->mdb, br);
@@ -448,6 +445,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
                if (p->port->state == BR_STATE_DISABLED)
                        goto unlock;
 
+               entry->state = p->state;
                rcu_assign_pointer(*pp, p->next);
                hlist_del_init(&p->mglist);
                del_timer(&p->timer);
index 742a6c27d7a222bc3c53c288b4a6915194310fe6..1285eaf5dc222e7cf75f4da796f2075f098105ae 100644 (file)
@@ -39,6 +39,16 @@ static void br_multicast_start_querier(struct net_bridge *br,
                                       struct bridge_mcast_own_query *query);
 static void br_multicast_add_router(struct net_bridge *br,
                                    struct net_bridge_port *port);
+static void br_ip4_multicast_leave_group(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        __be32 group,
+                                        __u16 vid);
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_leave_group(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        const struct in6_addr *group,
+                                        __u16 vid);
+#endif
 unsigned int br_mdb_rehash_seq;
 
 static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
@@ -1010,9 +1020,15 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
                        continue;
                }
 
-               err = br_ip4_multicast_add_group(br, port, group, vid);
-               if (err)
-                       break;
+               if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
+                    type == IGMPV3_MODE_IS_INCLUDE) &&
+                   ntohs(grec->grec_nsrcs) == 0) {
+                       br_ip4_multicast_leave_group(br, port, group, vid);
+               } else {
+                       err = br_ip4_multicast_add_group(br, port, group, vid);
+                       if (err)
+                               break;
+               }
        }
 
        return err;
@@ -1071,10 +1087,17 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
                        continue;
                }
 
-               err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
-                                                vid);
-               if (err)
-                       break;
+               if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
+                    grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
+                   ntohs(*nsrcs) == 0) {
+                       br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
+                                                    vid);
+               } else {
+                       err = br_ip6_multicast_add_group(br, port,
+                                                        &grec->grec_mca, vid);
+                       if (!err)
+                               break;
+               }
        }
 
        return err;
@@ -1393,8 +1416,7 @@ br_multicast_leave_group(struct net_bridge *br,
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) ||
-           (port && port->state == BR_STATE_DISABLED) ||
-           timer_pending(&other_query->timer))
+           (port && port->state == BR_STATE_DISABLED))
                goto out;
 
        mdb = mlock_dereference(br->mdb, br);
@@ -1402,6 +1424,31 @@ br_multicast_leave_group(struct net_bridge *br,
        if (!mp)
                goto out;
 
+       if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
+               struct net_bridge_port_group __rcu **pp;
+
+               for (pp = &mp->ports;
+                    (p = mlock_dereference(*pp, br)) != NULL;
+                    pp = &p->next) {
+                       if (p->port != port)
+                               continue;
+
+                       rcu_assign_pointer(*pp, p->next);
+                       hlist_del_init(&p->mglist);
+                       del_timer(&p->timer);
+                       call_rcu_bh(&p->rcu, br_multicast_free_pg);
+                       br_mdb_notify(br->dev, port, group, RTM_DELMDB);
+
+                       if (!mp->ports && !mp->mglist &&
+                           netif_running(br->dev))
+                               mod_timer(&mp->timer, jiffies);
+               }
+               goto out;
+       }
+
+       if (timer_pending(&other_query->timer))
+               goto out;
+
        if (br->multicast_querier) {
                __br_multicast_send_query(br, port, &mp->addr);
 
@@ -1427,28 +1474,6 @@ br_multicast_leave_group(struct net_bridge *br,
                }
        }
 
-       if (port && (port->flags & BR_MULTICAST_FAST_LEAVE)) {
-               struct net_bridge_port_group __rcu **pp;
-
-               for (pp = &mp->ports;
-                    (p = mlock_dereference(*pp, br)) != NULL;
-                    pp = &p->next) {
-                       if (p->port != port)
-                               continue;
-
-                       rcu_assign_pointer(*pp, p->next);
-                       hlist_del_init(&p->mglist);
-                       del_timer(&p->timer);
-                       call_rcu_bh(&p->rcu, br_multicast_free_pg);
-                       br_mdb_notify(br->dev, port, group, RTM_DELMDB);
-
-                       if (!mp->ports && !mp->mglist &&
-                           netif_running(br->dev))
-                               mod_timer(&mp->timer, jiffies);
-               }
-               goto out;
-       }
-
        now = jiffies;
        time = now + br->multicast_last_member_count *
                     br->multicast_last_member_interval;
@@ -1566,7 +1591,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
                break;
        }
 
-       if (skb_trimmed)
+       if (skb_trimmed && skb_trimmed != skb)
                kfree_skb(skb_trimmed);
 
        return err;
@@ -1611,7 +1636,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
                break;
        }
 
-       if (skb_trimmed)
+       if (skb_trimmed && skb_trimmed != skb)
                kfree_skb(skb_trimmed);
 
        return err;
index d89f4fac0bc507cb3faea7782d9791d48a552fea..c8b9bcfe997e48556cfc2633981e272e063f6880 100644 (file)
@@ -111,7 +111,7 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
 /* largest possible L2 header, see br_nf_dev_queue_xmit() */
 #define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN)
 
-#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) || IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
 struct brnf_frag_data {
        char mac[NF_BRIDGE_MAX_MAC_HEADER_LENGTH];
        u8 encap_size;
@@ -694,6 +694,7 @@ static int br_nf_push_frag_xmit(struct sock *sk, struct sk_buff *skb)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
 static int br_nf_ip_fragment(struct sock *sk, struct sk_buff *skb,
                             int (*output)(struct sock *, struct sk_buff *))
 {
@@ -712,6 +713,7 @@ static int br_nf_ip_fragment(struct sock *sk, struct sk_buff *skb,
 
        return ip_do_fragment(sk, skb, output);
 }
+#endif
 
 static unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
 {
@@ -742,7 +744,7 @@ static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb)
                struct brnf_frag_data *data;
 
                if (br_validate_ipv4(skb))
-                       return NF_DROP;
+                       goto drop;
 
                IPCB(skb)->frag_max_size = nf_bridge->frag_max_size;
 
@@ -767,7 +769,7 @@ static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb)
                struct brnf_frag_data *data;
 
                if (br_validate_ipv6(skb))
-                       return NF_DROP;
+                       goto drop;
 
                IP6CB(skb)->frag_max_size = nf_bridge->frag_max_size;
 
@@ -782,12 +784,16 @@ static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb)
 
                if (v6ops)
                        return v6ops->fragment(sk, skb, br_nf_push_frag_xmit);
-               else
-                       return -EMSGSIZE;
+
+               kfree_skb(skb);
+               return -EMSGSIZE;
        }
 #endif
        nf_bridge_info_free(skb);
        return br_dev_queue_push_xmit(sk, skb);
+ drop:
+       kfree_skb(skb);
+       return 0;
 }
 
 /* PF_BRIDGE/POST_ROUTING ********************************************/
index 6d12d2675c80920571a5788a2662f08a6cb73345..13b7d1e3d1850e9aa408b55287c8ad72c950081a 100644 (file)
@@ -104,7 +104,7 @@ int br_validate_ipv6(struct sk_buff *skb)
 {
        const struct ipv6hdr *hdr;
        struct net_device *dev = skb->dev;
-       struct inet6_dev *idev = in6_dev_get(skb->dev);
+       struct inet6_dev *idev = __in6_dev_get(skb->dev);
        u32 pkt_len;
        u8 ip6h_len = sizeof(struct ipv6hdr);
 
index 6b67ed3831de504c7f2d52e8cf7436c24365f183..4d74a0639c4ccd040b6371665e6a74f8dca6f800 100644 (file)
@@ -112,6 +112,8 @@ static inline size_t br_port_info_size(void)
                + nla_total_size(1)     /* IFLA_BRPORT_FAST_LEAVE */
                + nla_total_size(1)     /* IFLA_BRPORT_LEARNING */
                + nla_total_size(1)     /* IFLA_BRPORT_UNICAST_FLOOD */
+               + nla_total_size(1)     /* IFLA_BRPORT_PROXYARP */
+               + nla_total_size(1)     /* IFLA_BRPORT_PROXYARP_WIFI */
                + 0;
 }
 
@@ -457,6 +459,8 @@ static int br_afspec(struct net_bridge *br,
                if (nla_len(attr) != sizeof(struct bridge_vlan_info))
                        return -EINVAL;
                vinfo = nla_data(attr);
+               if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
+                       return -EINVAL;
                if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
                        if (vinfo_start)
                                return -EINVAL;
@@ -504,6 +508,8 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
        [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 },
        [IFLA_BRPORT_LEARNING]  = { .type = NLA_U8 },
        [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
+       [IFLA_BRPORT_PROXYARP]  = { .type = NLA_U8 },
+       [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
 };
 
 /* Change the state of the port and notify spanning tree */
@@ -691,9 +697,17 @@ static int br_port_slave_changelink(struct net_device *brdev,
                                    struct nlattr *tb[],
                                    struct nlattr *data[])
 {
+       struct net_bridge *br = netdev_priv(brdev);
+       int ret;
+
        if (!data)
                return 0;
-       return br_setport(br_port_get_rtnl(dev), data);
+
+       spin_lock_bh(&br->lock);
+       ret = br_setport(br_port_get_rtnl(dev), data);
+       spin_unlock_bh(&br->lock);
+
+       return ret;
 }
 
 static int br_port_fill_slave_info(struct sk_buff *skb,
index b4b6dab9c2859730d3ba9b5bc17f8302ddca6510..ed74ffaa851ff43d08c3edb4a158ab21af27e1a3 100644 (file)
@@ -209,8 +209,9 @@ void br_transmit_config(struct net_bridge_port *p)
                br_send_config_bpdu(p, &bpdu);
                p->topology_change_ack = 0;
                p->config_pending = 0;
-               mod_timer(&p->hold_timer,
-                         round_jiffies(jiffies + BR_HOLD_TIME));
+               if (p->br->stp_enabled == BR_KERNEL_STP)
+                       mod_timer(&p->hold_timer,
+                                 round_jiffies(jiffies + BR_HOLD_TIME));
        }
 }
 
index a2730e7196cd7080b96a441f5cc40591320862e5..4ca449a161320f7ef1c6f4864940e8557a7d18e3 100644 (file)
@@ -48,7 +48,8 @@ void br_stp_enable_bridge(struct net_bridge *br)
        struct net_bridge_port *p;
 
        spin_lock_bh(&br->lock);
-       mod_timer(&br->hello_timer, jiffies + br->hello_time);
+       if (br->stp_enabled == BR_KERNEL_STP)
+               mod_timer(&br->hello_timer, jiffies + br->hello_time);
        mod_timer(&br->gc_timer, jiffies + HZ/10);
 
        br_config_bpdu_generation(br);
@@ -127,6 +128,7 @@ static void br_stp_start(struct net_bridge *br)
        int r;
        char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
        char *envp[] = { NULL };
+       struct net_bridge_port *p;
 
        r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
 
@@ -140,6 +142,10 @@ static void br_stp_start(struct net_bridge *br)
        if (r == 0) {
                br->stp_enabled = BR_USER_STP;
                br_debug(br, "userspace STP started\n");
+               /* Stop hello and hold timers */
+               del_timer(&br->hello_timer);
+               list_for_each_entry(p, &br->port_list, list)
+                       del_timer(&p->hold_timer);
        } else {
                br->stp_enabled = BR_KERNEL_STP;
                br_debug(br, "using kernel STP\n");
@@ -156,12 +162,17 @@ static void br_stp_stop(struct net_bridge *br)
        int r;
        char *argv[] = { BR_STP_PROG, br->dev->name, "stop", NULL };
        char *envp[] = { NULL };
+       struct net_bridge_port *p;
 
        if (br->stp_enabled == BR_USER_STP) {
                r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
                br_info(br, "userspace STP stopped, return code %d\n", r);
 
                /* To start timers on any ports left in blocking */
+               mod_timer(&br->hello_timer, jiffies + br->hello_time);
+               list_for_each_entry(p, &br->port_list, list)
+                       mod_timer(&p->hold_timer,
+                                 round_jiffies(jiffies + BR_HOLD_TIME));
                spin_lock_bh(&br->lock);
                br_port_state_selection(br);
                spin_unlock_bh(&br->lock);
index 7caf7fae2d5b8aa369b924e1c87a47c343fb8954..5f0f5af0ec35bf8c216935713a9d5f803456e1ab 100644 (file)
@@ -40,7 +40,9 @@ static void br_hello_timer_expired(unsigned long arg)
        if (br->dev->flags & IFF_UP) {
                br_config_bpdu_generation(br);
 
-               mod_timer(&br->hello_timer, round_jiffies(jiffies + br->hello_time));
+               if (br->stp_enabled != BR_USER_STP)
+                       mod_timer(&br->hello_timer,
+                                 round_jiffies(jiffies + br->hello_time));
        }
        spin_unlock(&br->lock);
 }
index 3cc71b9f551756ca63b1299e95d9b6424e5afb72..cc858919108ee1f9645bce1046be8650a640d821 100644 (file)
@@ -121,12 +121,13 @@ static void caif_flow_ctrl(struct sock *sk, int mode)
  * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are
  * not dropped, but CAIF is sending flow off instead.
  */
-static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+static void caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
        unsigned long flags;
        struct sk_buff_head *list = &sk->sk_receive_queue;
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       bool queued = false;
 
        if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
                (unsigned int)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
@@ -139,7 +140,8 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        err = sk_filter(sk, skb);
        if (err)
-               return err;
+               goto out;
+
        if (!sk_rmem_schedule(sk, skb, skb->truesize) && rx_flow_is_on(cf_sk)) {
                set_rx_flow_off(cf_sk);
                net_dbg_ratelimited("sending flow OFF due to rmem_schedule\n");
@@ -147,21 +149,16 @@ static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        }
        skb->dev = NULL;
        skb_set_owner_r(skb, sk);
-       /* Cache the SKB length before we tack it onto the receive
-        * queue. Once it is added it no longer belongs to us and
-        * may be freed by other threads of control pulling packets
-        * from the queue.
-        */
        spin_lock_irqsave(&list->lock, flags);
-       if (!sock_flag(sk, SOCK_DEAD))
+       queued = !sock_flag(sk, SOCK_DEAD);
+       if (queued)
                __skb_queue_tail(list, skb);
        spin_unlock_irqrestore(&list->lock, flags);
-
-       if (!sock_flag(sk, SOCK_DEAD))
+out:
+       if (queued)
                sk->sk_data_ready(sk);
        else
                kfree_skb(skb);
-       return 0;
 }
 
 /* Packet Receive Callback function called from CAIF Stack */
index 7933e62a7318915327c7f0a9a8ead8beada40a2e..166d436196c14480184859e2bcaadeb7c5514f3a 100644 (file)
@@ -89,6 +89,8 @@ struct timer_list can_stattimer;   /* timer for statistics update */
 struct s_stats    can_stats;       /* packet statistics */
 struct s_pstats   can_pstats;      /* receive list statistics */
 
+static atomic_t skbcounter = ATOMIC_INIT(0);
+
 /*
  * af_can socket functions
  */
@@ -310,12 +312,8 @@ int can_send(struct sk_buff *skb, int loop)
                return err;
        }
 
-       if (newskb) {
-               if (!(newskb->tstamp.tv64))
-                       __net_timestamp(newskb);
-
+       if (newskb)
                netif_rx_ni(newskb);
-       }
 
        /* update statistics */
        can_stats.tx_frames++;
@@ -683,6 +681,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
        can_stats.rx_frames++;
        can_stats.rx_frames_delta++;
 
+       /* create non-zero unique skb identifier together with *skb */
+       while (!(can_skb_prv(skb)->skbcnt))
+               can_skb_prv(skb)->skbcnt = atomic_inc_return(&skbcounter);
+
        rcu_read_lock();
 
        /* deliver the packet to sockets listening on all devices */
index b523453585be7f56f1e04eb97977b2eb4f90dadb..a1ba6875c2a2073d55b6f797e16d88baed3af3d1 100644 (file)
@@ -261,6 +261,7 @@ static void bcm_can_tx(struct bcm_op *op)
 
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
+       can_skb_prv(skb)->skbcnt = 0;
 
        memcpy(skb_put(skb, CFSIZ), cf, CFSIZ);
 
@@ -1217,6 +1218,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
        }
 
        can_skb_prv(skb)->ifindex = dev->ifindex;
+       can_skb_prv(skb)->skbcnt = 0;
        skb->dev = dev;
        can_skb_set_owner(skb, sk);
        err = can_send(skb, 1); /* send with loopback */
index 31b9748cbb4ec6c1caa9ddc9e3a80609077a81eb..2e67b1423cd32d82cbf34742bf9208cb494eaa28 100644 (file)
@@ -75,7 +75,7 @@ MODULE_ALIAS("can-proto-1");
  */
 
 struct uniqframe {
-       ktime_t tstamp;
+       int skbcnt;
        const struct sk_buff *skb;
        unsigned int join_rx_count;
 };
@@ -133,7 +133,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
 
        /* eliminate multiple filter matches for the same skb */
        if (this_cpu_ptr(ro->uniq)->skb == oskb &&
-           ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) {
+           this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) {
                if (ro->join_filters) {
                        this_cpu_inc(ro->uniq->join_rx_count);
                        /* drop frame until all enabled filters matched */
@@ -144,7 +144,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
                }
        } else {
                this_cpu_ptr(ro->uniq)->skb = oskb;
-               this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp;
+               this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt;
                this_cpu_ptr(ro->uniq)->join_rx_count = 1;
                /* drop first frame to check all enabled filters? */
                if (ro->join_filters && ro->count > 1)
@@ -749,6 +749,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        can_skb_reserve(skb);
        can_skb_prv(skb)->ifindex = dev->ifindex;
+       can_skb_prv(skb)->skbcnt = 0;
 
        err = memcpy_from_msg(skb_put(skb, size), msg, size);
        if (err < 0)
index cb7db320dd276aa0107d8e484270e3e8fb61dd6a..f30329f726418bdc2e82bb5aced4c3634e215850 100644 (file)
@@ -9,6 +9,7 @@
 #include <keys/ceph-type.h>
 #include <linux/module.h>
 #include <linux/mount.h>
+#include <linux/nsproxy.h>
 #include <linux/parser.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
@@ -16,8 +17,6 @@
 #include <linux/statfs.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
-#include <linux/nsproxy.h>
-#include <net/net_namespace.h>
 
 
 #include <linux/ceph/ceph_features.h>
@@ -131,6 +130,13 @@ int ceph_compare_options(struct ceph_options *new_opt,
        int i;
        int ret;
 
+       /*
+        * Don't bother comparing options if network namespaces don't
+        * match.
+        */
+       if (!net_eq(current->nsproxy->net_ns, read_pnet(&client->msgr.net)))
+               return -1;
+
        ret = memcmp(opt1, opt2, ofs);
        if (ret)
                return ret;
@@ -335,9 +341,6 @@ ceph_parse_options(char *options, const char *dev_name,
        int err = -ENOMEM;
        substring_t argstr[MAX_OPT_ARGS];
 
-       if (current->nsproxy->net_ns != &init_net)
-               return ERR_PTR(-EINVAL);
-
        opt = kzalloc(sizeof(*opt), GFP_KERNEL);
        if (!opt)
                return ERR_PTR(-ENOMEM);
@@ -608,6 +611,7 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
 fail_monc:
        ceph_monc_stop(&client->monc);
 fail:
+       ceph_messenger_fini(&client->msgr);
        kfree(client);
        return ERR_PTR(err);
 }
@@ -621,8 +625,8 @@ void ceph_destroy_client(struct ceph_client *client)
 
        /* unmount */
        ceph_osdc_stop(&client->osdc);
-
        ceph_monc_stop(&client->monc);
+       ceph_messenger_fini(&client->msgr);
 
        ceph_debugfs_client_cleanup(client);
 
index 1679f47280e2678202238e667c1b617c7665d5fa..e3be1d22a2477dd2d9e271a4594d70ebdb1148e7 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/inet.h>
 #include <linux/kthread.h>
 #include <linux/net.h>
+#include <linux/nsproxy.h>
 #include <linux/slab.h>
 #include <linux/socket.h>
 #include <linux/string.h>
@@ -479,7 +480,7 @@ static int ceph_tcp_connect(struct ceph_connection *con)
        int ret;
 
        BUG_ON(con->sock);
-       ret = sock_create_kern(&init_net, con->peer_addr.in_addr.ss_family,
+       ret = sock_create_kern(read_pnet(&con->msgr->net), paddr->ss_family,
                               SOCK_STREAM, IPPROTO_TCP, &sock);
        if (ret)
                return ret;
@@ -1731,17 +1732,17 @@ static int verify_hello(struct ceph_connection *con)
 
 static bool addr_is_blank(struct sockaddr_storage *ss)
 {
+       struct in_addr *addr = &((struct sockaddr_in *)ss)->sin_addr;
+       struct in6_addr *addr6 = &((struct sockaddr_in6 *)ss)->sin6_addr;
+
        switch (ss->ss_family) {
        case AF_INET:
-               return ((struct sockaddr_in *)ss)->sin_addr.s_addr == 0;
+               return addr->s_addr == htonl(INADDR_ANY);
        case AF_INET6:
-               return
-                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[0] == 0 &&
-                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[1] == 0 &&
-                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[2] == 0 &&
-                    ((struct sockaddr_in6 *)ss)->sin6_addr.s6_addr32[3] == 0;
+               return ipv6_addr_any(addr6);
+       default:
+               return true;
        }
-       return false;
 }
 
 static int addr_port(struct sockaddr_storage *ss)
@@ -2944,11 +2945,18 @@ void ceph_messenger_init(struct ceph_messenger *msgr,
        msgr->tcp_nodelay = tcp_nodelay;
 
        atomic_set(&msgr->stopping, 0);
+       write_pnet(&msgr->net, get_net(current->nsproxy->net_ns));
 
        dout("%s %p\n", __func__, msgr);
 }
 EXPORT_SYMBOL(ceph_messenger_init);
 
+void ceph_messenger_fini(struct ceph_messenger *msgr)
+{
+       put_net(read_pnet(&msgr->net));
+}
+EXPORT_SYMBOL(ceph_messenger_fini);
+
 static void clear_standby(struct ceph_connection *con)
 {
        /* come back from STANDBY? */
index b80fb91bb3f7e8dc630663cb5e012dc97ac6924f..617088aee21d41ba98d4ef5ebee5d6c002efe029 100644 (file)
@@ -131,6 +131,35 @@ out_noerr:
        goto out;
 }
 
+static struct sk_buff *skb_set_peeked(struct sk_buff *skb)
+{
+       struct sk_buff *nskb;
+
+       if (skb->peeked)
+               return skb;
+
+       /* We have to unshare an skb before modifying it. */
+       if (!skb_shared(skb))
+               goto done;
+
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (!nskb)
+               return ERR_PTR(-ENOMEM);
+
+       skb->prev->next = nskb;
+       skb->next->prev = nskb;
+       nskb->prev = skb->prev;
+       nskb->next = skb->next;
+
+       consume_skb(skb);
+       skb = nskb;
+
+done:
+       skb->peeked = 1;
+
+       return skb;
+}
+
 /**
  *     __skb_recv_datagram - Receive a datagram skbuff
  *     @sk: socket
@@ -165,7 +194,9 @@ out_noerr:
 struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                                    int *peeked, int *off, int *err)
 {
+       struct sk_buff_head *queue = &sk->sk_receive_queue;
        struct sk_buff *skb, *last;
+       unsigned long cpu_flags;
        long timeo;
        /*
         * Caller is allowed not to check sk->sk_err before skb_recv_datagram()
@@ -184,8 +215,6 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                 * Look at current nfs client by the way...
                 * However, this function was correct in any case. 8)
                 */
-               unsigned long cpu_flags;
-               struct sk_buff_head *queue = &sk->sk_receive_queue;
                int _off = *off;
 
                last = (struct sk_buff *)queue;
@@ -199,7 +228,12 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                                        _off -= skb->len;
                                        continue;
                                }
-                               skb->peeked = 1;
+
+                               skb = skb_set_peeked(skb);
+                               error = PTR_ERR(skb);
+                               if (IS_ERR(skb))
+                                       goto unlock_err;
+
                                atomic_inc(&skb->users);
                        } else
                                __skb_unlink(skb, queue);
@@ -223,6 +257,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
 
        return NULL;
 
+unlock_err:
+       spin_unlock_irqrestore(&queue->lock, cpu_flags);
 no_packet:
        *err = error;
        return NULL;
@@ -622,7 +658,8 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
                    !skb->csum_complete_sw)
                        netdev_rx_csum_fault(skb->dev);
        }
-       skb->csum_valid = !sum;
+       if (!skb_shared(skb))
+               skb->csum_valid = !sum;
        return sum;
 }
 EXPORT_SYMBOL(__skb_checksum_complete_head);
@@ -642,11 +679,13 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
                        netdev_rx_csum_fault(skb->dev);
        }
 
-       /* Save full packet checksum */
-       skb->csum = csum;
-       skb->ip_summed = CHECKSUM_COMPLETE;
-       skb->csum_complete_sw = 1;
-       skb->csum_valid = !sum;
+       if (!skb_shared(skb)) {
+               /* Save full packet checksum */
+               skb->csum = csum;
+               skb->ip_summed = CHECKSUM_COMPLETE;
+               skb->csum_complete_sw = 1;
+               skb->csum_valid = !sum;
+       }
 
        return sum;
 }
index 6778a9999d525307d5bd41a1750a6e96a6e22bf3..a8e4dd4302853702fef7fb1462fbdeb8a38f45e1 100644 (file)
@@ -677,10 +677,6 @@ int dev_get_iflink(const struct net_device *dev)
        if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink)
                return dev->netdev_ops->ndo_get_iflink(dev);
 
-       /* If dev->rtnl_link_ops is set, it's a virtual interface. */
-       if (dev->rtnl_link_ops)
-               return 0;
-
        return dev->ifindex;
 }
 EXPORT_SYMBOL(dev_get_iflink);
@@ -3452,6 +3448,8 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
        local_irq_save(flags);
 
        rps_lock(sd);
+       if (!netif_running(skb->dev))
+               goto drop;
        qlen = skb_queue_len(&sd->input_pkt_queue);
        if (qlen <= netdev_max_backlog && !skb_flow_limit(skb, qlen)) {
                if (qlen) {
@@ -3473,6 +3471,7 @@ enqueue:
                goto enqueue;
        }
 
+drop:
        sd->dropped++;
        rps_unlock(sd);
 
@@ -3775,8 +3774,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
 
        pt_prev = NULL;
 
-       rcu_read_lock();
-
 another_round:
        skb->skb_iif = skb->dev->ifindex;
 
@@ -3786,7 +3783,7 @@ another_round:
            skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
                skb = skb_vlan_untag(skb);
                if (unlikely(!skb))
-                       goto unlock;
+                       goto out;
        }
 
 #ifdef CONFIG_NET_CLS_ACT
@@ -3816,10 +3813,10 @@ skip_taps:
        if (static_key_false(&ingress_needed)) {
                skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
                if (!skb)
-                       goto unlock;
+                       goto out;
 
                if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0)
-                       goto unlock;
+                       goto out;
        }
 #endif
 #ifdef CONFIG_NET_CLS_ACT
@@ -3837,7 +3834,7 @@ ncls:
                if (vlan_do_receive(&skb))
                        goto another_round;
                else if (unlikely(!skb))
-                       goto unlock;
+                       goto out;
        }
 
        rx_handler = rcu_dereference(skb->dev->rx_handler);
@@ -3849,7 +3846,7 @@ ncls:
                switch (rx_handler(&skb)) {
                case RX_HANDLER_CONSUMED:
                        ret = NET_RX_SUCCESS;
-                       goto unlock;
+                       goto out;
                case RX_HANDLER_ANOTHER:
                        goto another_round;
                case RX_HANDLER_EXACT:
@@ -3903,8 +3900,7 @@ drop:
                ret = NET_RX_DROP;
        }
 
-unlock:
-       rcu_read_unlock();
+out:
        return ret;
 }
 
@@ -3935,29 +3931,30 @@ static int __netif_receive_skb(struct sk_buff *skb)
 
 static int netif_receive_skb_internal(struct sk_buff *skb)
 {
+       int ret;
+
        net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        if (skb_defer_rx_timestamp(skb))
                return NET_RX_SUCCESS;
 
+       rcu_read_lock();
+
 #ifdef CONFIG_RPS
        if (static_key_false(&rps_needed)) {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
-               int cpu, ret;
-
-               rcu_read_lock();
-
-               cpu = get_rps_cpu(skb->dev, skb, &rflow);
+               int cpu = get_rps_cpu(skb->dev, skb, &rflow);
 
                if (cpu >= 0) {
                        ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
                        rcu_read_unlock();
                        return ret;
                }
-               rcu_read_unlock();
        }
 #endif
-       return __netif_receive_skb(skb);
+       ret = __netif_receive_skb(skb);
+       rcu_read_unlock();
+       return ret;
 }
 
 /**
@@ -4502,8 +4499,10 @@ static int process_backlog(struct napi_struct *napi, int quota)
                struct sk_buff *skb;
 
                while ((skb = __skb_dequeue(&sd->process_queue))) {
+                       rcu_read_lock();
                        local_irq_enable();
                        __netif_receive_skb(skb);
+                       rcu_read_unlock();
                        local_irq_disable();
                        input_queue_head_incr(sd);
                        if (++work >= quota) {
@@ -6139,6 +6138,7 @@ static void rollback_registered_many(struct list_head *head)
                unlist_netdevice(dev);
 
                dev->reg_state = NETREG_UNREGISTERING;
+               on_each_cpu(flush_backlog, dev, 1);
        }
 
        synchronize_net();
@@ -6409,7 +6409,8 @@ static int netif_alloc_netdev_queues(struct net_device *dev)
        struct netdev_queue *tx;
        size_t sz = count * sizeof(*tx);
 
-       BUG_ON(count < 1 || count > 0xffff);
+       if (count < 1 || count > 0xffff)
+               return -EINVAL;
 
        tx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
        if (!tx) {
@@ -6773,8 +6774,6 @@ void netdev_run_todo(void)
 
                dev->reg_state = NETREG_UNREGISTERED;
 
-               on_each_cpu(flush_backlog, dev, 1);
-
                netdev_wait_allrefs(dev);
 
                /* paranoia */
index e956ce6d13782f2da0a229cabafef663665159eb..002144bea93517d7e2e5b2c0ac00e70c028174a2 100644 (file)
@@ -284,7 +284,9 @@ void dst_release(struct dst_entry *dst)
                int newrefcnt;
 
                newrefcnt = atomic_dec_return(&dst->__refcnt);
-               WARN_ON(newrefcnt < 0);
+               if (unlikely(newrefcnt < 0))
+                       net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
+                                            __func__, dst, newrefcnt);
                if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt)
                        call_rcu(&dst->rcu_head, dst_destroy_rcu);
        }
index 9dfb88a933e7c25ac5125570c2fd0edf4696c1cb..92d886f4adcbd9feebbf9ae5eb084f8ba5fa946b 100644 (file)
@@ -66,7 +66,7 @@
 
    NOTES.
 
-   * avbps is scaled by 2^5, avpps is scaled by 2^10.
+   * avbps and avpps are scaled by 2^5.
    * both values are reported as 32 bit unsigned values. bps can
      overflow for fast links : max speed being 34360Mbit/sec
    * Minimal interval is HZ/4=250msec (it is the greatest common divisor
@@ -85,10 +85,10 @@ struct gen_estimator
        struct gnet_stats_rate_est64    *rate_est;
        spinlock_t              *stats_lock;
        int                     ewma_log;
+       u32                     last_packets;
+       unsigned long           avpps;
        u64                     last_bytes;
        u64                     avbps;
-       u32                     last_packets;
-       u32                     avpps;
        struct rcu_head         e_rcu;
        struct rb_node          node;
        struct gnet_stats_basic_cpu __percpu *cpu_bstats;
@@ -118,8 +118,8 @@ static void est_timer(unsigned long arg)
        rcu_read_lock();
        list_for_each_entry_rcu(e, &elist[idx].list, list) {
                struct gnet_stats_basic_packed b = {0};
+               unsigned long rate;
                u64 brate;
-               u32 rate;
 
                spin_lock(e->stats_lock);
                read_lock(&est_lock);
@@ -133,10 +133,11 @@ static void est_timer(unsigned long arg)
                e->avbps += (brate >> e->ewma_log) - (e->avbps >> e->ewma_log);
                e->rate_est->bps = (e->avbps+0xF)>>5;
 
-               rate = (b.packets - e->last_packets)<<(12 - idx);
+               rate = b.packets - e->last_packets;
+               rate <<= (7 - idx);
                e->last_packets = b.packets;
                e->avpps += (rate >> e->ewma_log) - (e->avpps >> e->ewma_log);
-               e->rate_est->pps = (e->avpps+0x1FF)>>10;
+               e->rate_est->pps = (e->avpps + 0xF) >> 5;
 skip:
                read_unlock(&est_lock);
                spin_unlock(e->stats_lock);
index 1f2a126f4ffa07a6e50cd2b57a6042afca3ee3ad..6441f47b1a8ffc78731896fd4ab1b12db43f0992 100644 (file)
@@ -23,7 +23,8 @@ static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state
 
 struct cgroup_cls_state *task_cls_state(struct task_struct *p)
 {
-       return css_cls_state(task_css(p, net_cls_cgrp_id));
+       return css_cls_state(task_css_check(p, net_cls_cgrp_id,
+                                           rcu_read_lock_bh_held()));
 }
 EXPORT_SYMBOL_GPL(task_cls_state);
 
index 05badbb588659eaba8db986900f22f104d498dc0..1cbd209192eacd6b7ec9a13f8180a5138760fc7e 100644 (file)
@@ -3514,8 +3514,6 @@ static int pktgen_thread_worker(void *arg)
 
        set_freezable();
 
-       __set_current_state(TASK_RUNNING);
-
        while (!kthread_should_stop()) {
                pkt_dev = next_to_run(t);
 
@@ -3560,7 +3558,6 @@ static int pktgen_thread_worker(void *arg)
 
                try_to_freeze();
        }
-       set_current_state(TASK_INTERRUPTIBLE);
 
        pr_debug("%s stopping all device\n", t->tsk->comm);
        pktgen_stop(t);
@@ -3571,13 +3568,6 @@ static int pktgen_thread_worker(void *arg)
        pr_debug("%s removing thread\n", t->tsk->comm);
        pktgen_rem_thread(t);
 
-       /* Wait for kthread_stop */
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-       }
-       __set_current_state(TASK_RUNNING);
-
        return 0;
 }
 
@@ -3769,6 +3759,7 @@ static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn)
        }
 
        t->net = pn;
+       get_task_struct(p);
        wake_up_process(p);
        wait_for_completion(&t->start_done);
 
@@ -3891,6 +3882,7 @@ static void __net_exit pg_net_exit(struct net *net)
                t = list_entry(q, struct pktgen_thread, th_list);
                list_del(&t->th_list);
                kthread_stop(t->tsk);
+               put_task_struct(t->tsk);
                kfree(t);
        }
 
index 87b22c0bc08c2f33fa31948b8b2604f48b8009bc..b42f0e26f89e4cf2e37a8329da549eb5cd1200c5 100644 (file)
@@ -103,10 +103,16 @@ void reqsk_queue_destroy(struct request_sock_queue *queue)
                        spin_lock_bh(&queue->syn_wait_lock);
                        while ((req = lopt->syn_table[i]) != NULL) {
                                lopt->syn_table[i] = req->dl_next;
+                               /* Because of following del_timer_sync(),
+                                * we must release the spinlock here
+                                * or risk a dead lock.
+                                */
+                               spin_unlock_bh(&queue->syn_wait_lock);
                                atomic_inc(&lopt->qlen_dec);
-                               if (del_timer(&req->rsk_timer))
+                               if (del_timer_sync(&req->rsk_timer))
                                        reqsk_put(req);
                                reqsk_put(req);
+                               spin_lock_bh(&queue->syn_wait_lock);
                        }
                        spin_unlock_bh(&queue->syn_wait_lock);
                }
index 01ced4a889e04b02648d017985a2b53bc293be19..dc004b1e1f8515250bb7c7f284b047d2f961f083 100644 (file)
@@ -1328,10 +1328,6 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
        [IFLA_INFO_SLAVE_DATA]  = { .type = NLA_NESTED },
 };
 
-static const struct nla_policy ifla_vfinfo_policy[IFLA_VF_INFO_MAX+1] = {
-       [IFLA_VF_INFO]          = { .type = NLA_NESTED },
-};
-
 static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
        [IFLA_VF_MAC]           = { .len = sizeof(struct ifla_vf_mac) },
        [IFLA_VF_VLAN]          = { .len = sizeof(struct ifla_vf_vlan) },
@@ -1488,96 +1484,98 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
        return 0;
 }
 
-static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
+static int do_setvfinfo(struct net_device *dev, struct nlattr **tb)
 {
-       int rem, err = -EINVAL;
-       struct nlattr *vf;
        const struct net_device_ops *ops = dev->netdev_ops;
+       int err = -EINVAL;
 
-       nla_for_each_nested(vf, attr, rem) {
-               switch (nla_type(vf)) {
-               case IFLA_VF_MAC: {
-                       struct ifla_vf_mac *ivm;
-                       ivm = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_mac)
-                               err = ops->ndo_set_vf_mac(dev, ivm->vf,
-                                                         ivm->mac);
-                       break;
-               }
-               case IFLA_VF_VLAN: {
-                       struct ifla_vf_vlan *ivv;
-                       ivv = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_vlan)
-                               err = ops->ndo_set_vf_vlan(dev, ivv->vf,
-                                                          ivv->vlan,
-                                                          ivv->qos);
-                       break;
-               }
-               case IFLA_VF_TX_RATE: {
-                       struct ifla_vf_tx_rate *ivt;
-                       struct ifla_vf_info ivf;
-                       ivt = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_get_vf_config)
-                               err = ops->ndo_get_vf_config(dev, ivt->vf,
-                                                            &ivf);
-                       if (err)
-                               break;
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_rate)
-                               err = ops->ndo_set_vf_rate(dev, ivt->vf,
-                                                          ivf.min_tx_rate,
-                                                          ivt->rate);
-                       break;
-               }
-               case IFLA_VF_RATE: {
-                       struct ifla_vf_rate *ivt;
-                       ivt = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_rate)
-                               err = ops->ndo_set_vf_rate(dev, ivt->vf,
-                                                          ivt->min_tx_rate,
-                                                          ivt->max_tx_rate);
-                       break;
-               }
-               case IFLA_VF_SPOOFCHK: {
-                       struct ifla_vf_spoofchk *ivs;
-                       ivs = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_spoofchk)
-                               err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
-                                                              ivs->setting);
-                       break;
-               }
-               case IFLA_VF_LINK_STATE: {
-                       struct ifla_vf_link_state *ivl;
-                       ivl = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_link_state)
-                               err = ops->ndo_set_vf_link_state(dev, ivl->vf,
-                                                                ivl->link_state);
-                       break;
-               }
-               case IFLA_VF_RSS_QUERY_EN: {
-                       struct ifla_vf_rss_query_en *ivrssq_en;
+       if (tb[IFLA_VF_MAC]) {
+               struct ifla_vf_mac *ivm = nla_data(tb[IFLA_VF_MAC]);
 
-                       ivrssq_en = nla_data(vf);
-                       err = -EOPNOTSUPP;
-                       if (ops->ndo_set_vf_rss_query_en)
-                               err = ops->ndo_set_vf_rss_query_en(dev,
-                                                           ivrssq_en->vf,
-                                                           ivrssq_en->setting);
-                       break;
-               }
-               default:
-                       err = -EINVAL;
-                       break;
-               }
-               if (err)
-                       break;
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_mac)
+                       err = ops->ndo_set_vf_mac(dev, ivm->vf,
+                                                 ivm->mac);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[IFLA_VF_VLAN]) {
+               struct ifla_vf_vlan *ivv = nla_data(tb[IFLA_VF_VLAN]);
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_vlan)
+                       err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan,
+                                                  ivv->qos);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[IFLA_VF_TX_RATE]) {
+               struct ifla_vf_tx_rate *ivt = nla_data(tb[IFLA_VF_TX_RATE]);
+               struct ifla_vf_info ivf;
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_get_vf_config)
+                       err = ops->ndo_get_vf_config(dev, ivt->vf, &ivf);
+               if (err < 0)
+                       return err;
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_rate)
+                       err = ops->ndo_set_vf_rate(dev, ivt->vf,
+                                                  ivf.min_tx_rate,
+                                                  ivt->rate);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[IFLA_VF_RATE]) {
+               struct ifla_vf_rate *ivt = nla_data(tb[IFLA_VF_RATE]);
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_rate)
+                       err = ops->ndo_set_vf_rate(dev, ivt->vf,
+                                                  ivt->min_tx_rate,
+                                                  ivt->max_tx_rate);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[IFLA_VF_SPOOFCHK]) {
+               struct ifla_vf_spoofchk *ivs = nla_data(tb[IFLA_VF_SPOOFCHK]);
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_spoofchk)
+                       err = ops->ndo_set_vf_spoofchk(dev, ivs->vf,
+                                                      ivs->setting);
+               if (err < 0)
+                       return err;
        }
+
+       if (tb[IFLA_VF_LINK_STATE]) {
+               struct ifla_vf_link_state *ivl = nla_data(tb[IFLA_VF_LINK_STATE]);
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_link_state)
+                       err = ops->ndo_set_vf_link_state(dev, ivl->vf,
+                                                        ivl->link_state);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[IFLA_VF_RSS_QUERY_EN]) {
+               struct ifla_vf_rss_query_en *ivrssq_en;
+
+               err = -EOPNOTSUPP;
+               ivrssq_en = nla_data(tb[IFLA_VF_RSS_QUERY_EN]);
+               if (ops->ndo_set_vf_rss_query_en)
+                       err = ops->ndo_set_vf_rss_query_en(dev, ivrssq_en->vf,
+                                                          ivrssq_en->setting);
+               if (err < 0)
+                       return err;
+       }
+
        return err;
 }
 
@@ -1773,14 +1771,21 @@ static int do_setlink(const struct sk_buff *skb,
        }
 
        if (tb[IFLA_VFINFO_LIST]) {
+               struct nlattr *vfinfo[IFLA_VF_MAX + 1];
                struct nlattr *attr;
                int rem;
+
                nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) {
-                       if (nla_type(attr) != IFLA_VF_INFO) {
+                       if (nla_type(attr) != IFLA_VF_INFO ||
+                           nla_len(attr) < NLA_HDRLEN) {
                                err = -EINVAL;
                                goto errout;
                        }
-                       err = do_setvfinfo(dev, attr);
+                       err = nla_parse_nested(vfinfo, IFLA_VF_MAX, attr,
+                                              ifla_vf_policy);
+                       if (err < 0)
+                               goto errout;
+                       err = do_setvfinfo(dev, vfinfo);
                        if (err < 0)
                                goto errout;
                        status |= DO_SETLINK_NOTIFY;
@@ -1799,10 +1804,13 @@ static int do_setlink(const struct sk_buff *skb,
                        goto errout;
 
                nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) {
-                       if (nla_type(attr) != IFLA_VF_PORT)
-                               continue;
-                       err = nla_parse_nested(port, IFLA_PORT_MAX,
-                               attr, ifla_port_policy);
+                       if (nla_type(attr) != IFLA_VF_PORT ||
+                           nla_len(attr) < NLA_HDRLEN) {
+                               err = -EINVAL;
+                               goto errout;
+                       }
+                       err = nla_parse_nested(port, IFLA_PORT_MAX, attr,
+                                              ifla_port_policy);
                        if (err < 0)
                                goto errout;
                        if (!port[IFLA_PORT_VF]) {
index b6a19ca0f99e49c7406f1fedb6c59433bbd7fd38..7b84330e5d30693cf63fe2d04b7f64f2b8893362 100644 (file)
@@ -340,7 +340,7 @@ struct sk_buff *build_skb(void *data, unsigned int frag_size)
 
        if (skb && frag_size) {
                skb->head_frag = 1;
-               if (virt_to_head_page(data)->pfmemalloc)
+               if (page_is_pfmemalloc(virt_to_head_page(data)))
                        skb->pfmemalloc = 1;
        }
        return skb;
@@ -4022,8 +4022,8 @@ EXPORT_SYMBOL(skb_checksum_setup);
  * Otherwise returns the provided skb. Returns NULL in error cases
  * (e.g. transport_len exceeds skb length or out-of-memory).
  *
- * Caller needs to set the skb transport header and release the returned skb.
- * Provided skb is consumed.
+ * Caller needs to set the skb transport header and free any returned skb if it
+ * differs from the provided skb.
  */
 static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
                                               unsigned int transport_len)
@@ -4032,16 +4032,12 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
        unsigned int len = skb_transport_offset(skb) + transport_len;
        int ret;
 
-       if (skb->len < len) {
-               kfree_skb(skb);
+       if (skb->len < len)
                return NULL;
-       } else if (skb->len == len) {
+       else if (skb->len == len)
                return skb;
-       }
 
        skb_chk = skb_clone(skb, GFP_ATOMIC);
-       kfree_skb(skb);
-
        if (!skb_chk)
                return NULL;
 
@@ -4066,8 +4062,8 @@ static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb,
  * If the skb has data beyond the given transport length, then a
  * trimmed & cloned skb is checked and returned.
  *
- * Caller needs to set the skb transport header and release the returned skb.
- * Provided skb is consumed.
+ * Caller needs to set the skb transport header and free any returned skb if it
+ * differs from the provided skb.
  */
 struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
                                     unsigned int transport_len,
@@ -4079,23 +4075,26 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
 
        skb_chk = skb_checksum_maybe_trim(skb, transport_len);
        if (!skb_chk)
-               return NULL;
+               goto err;
 
-       if (!pskb_may_pull(skb_chk, offset)) {
-               kfree_skb(skb_chk);
-               return NULL;
-       }
+       if (!pskb_may_pull(skb_chk, offset))
+               goto err;
 
        __skb_pull(skb_chk, offset);
        ret = skb_chkf(skb_chk);
        __skb_push(skb_chk, offset);
 
-       if (ret) {
-               kfree_skb(skb_chk);
-               return NULL;
-       }
+       if (ret)
+               goto err;
 
        return skb_chk;
+
+err:
+       if (skb_chk && skb_chk != skb)
+               kfree_skb(skb_chk);
+
+       return NULL;
+
 }
 EXPORT_SYMBOL(skb_checksum_trimmed);
 
index 08f16db46070a1520fcdd6892477093e9474af4f..193901d097577a88e7fea3f59450cc041942f8fa 100644 (file)
@@ -1497,7 +1497,8 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                sock_copy(newsk, sk);
 
                /* SANITY */
-               get_net(sock_net(newsk));
+               if (likely(newsk->sk_net_refcnt))
+                       get_net(sock_net(newsk));
                sk_node_init(&newsk->sk_node);
                sock_lock_init(newsk);
                bh_lock_sock(newsk);
@@ -1967,20 +1968,21 @@ static void __release_sock(struct sock *sk)
  * sk_wait_data - wait for data to arrive at sk_receive_queue
  * @sk:    sock to wait on
  * @timeo: for how long
+ * @skb:   last skb seen on sk_receive_queue
  *
  * Now socket state including sk->sk_err is changed only under lock,
  * hence we may omit checks after joining wait queue.
  * We check receive queue before schedule() only as optimization;
  * it is very likely that release_sock() added new data.
  */
-int sk_wait_data(struct sock *sk, long *timeo)
+int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb)
 {
        int rc;
        DEFINE_WAIT(wait);
 
        prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-       rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue));
+       rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb);
        clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        finish_wait(sk_sleep(sk), &wait);
        return rc;
index 52a94016526d3c595a71f4affac1a24251f964d7..b5cf13a2800923486ad597c296a66145bc248596 100644 (file)
@@ -886,7 +886,7 @@ verify_sock_status:
                        break;
                }
 
-               sk_wait_data(sk, &timeo);
+               sk_wait_data(sk, &timeo, NULL);
                continue;
        found_ok_skb:
                if (len > skb->len)
index 392e29a0227dbf4aa4870d73c5ef333db528b675..b445d492c115382b9ecd25cbceb3e47053263387 100644 (file)
@@ -630,7 +630,7 @@ static int dsa_of_probe(struct device *dev)
                        continue;
 
                cd->sw_addr = be32_to_cpup(sw_addr);
-               if (cd->sw_addr > PHY_MAX_ADDR)
+               if (cd->sw_addr >= PHY_MAX_ADDR)
                        continue;
 
                if (!of_property_read_u32(child, "eeprom-length", &eeprom_len))
@@ -642,6 +642,8 @@ static int dsa_of_probe(struct device *dev)
                                continue;
 
                        port_index = be32_to_cpup(port_reg);
+                       if (port_index >= DSA_MAX_PORTS)
+                               break;
 
                        port_name = of_get_property(port, "label", NULL);
                        if (!port_name)
@@ -666,8 +668,6 @@ static int dsa_of_probe(struct device *dev)
                                        goto out_free_chip;
                        }
 
-                       if (port_index == DSA_MAX_PORTS)
-                               break;
                }
        }
 
index 0917123790eaf09b001c97a733039185fdb0a800..35c47ddd04f0ee3eb965fd99b06bab2ee4670774 100644 (file)
@@ -756,7 +756,8 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,
                return -ENODEV;
 
        /* Use already configured phy mode */
-       p->phy_interface = p->phy->interface;
+       if (p->phy_interface == PHY_INTERFACE_MODE_NA)
+               p->phy_interface = p->phy->interface;
        phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
                           p->phy_interface);
 
index f46e4d1306f26363643c054f64d62a9acb39151e..214d44aef35b5cd69ffe859138938e311c717cc3 100644 (file)
@@ -207,7 +207,7 @@ found:
        } else {
                fq->q.meat += skb->len;
        }
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
            fq->q.meat == fq->q.len) {
@@ -287,7 +287,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
                clone->data_len = clone->len;
                head->data_len -= clone->len;
                head->len -= clone->len;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        WARN_ON(head == NULL);
@@ -310,7 +310,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&fq->q, sum_truesize);
+       sub_frag_mem_limit(fq->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
index 933a92820d265e07b8c42300c7be6742565723b5..6c8b1fbafce8e39cb7c4c058fa653dd9d2f52f9e 100644 (file)
@@ -1017,14 +1017,16 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
 
        neigh = neigh_lookup(&arp_tbl, &ip, dev);
        if (neigh) {
-               read_lock_bh(&neigh->lock);
-               memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
-               r->arp_flags = arp_state_to_flags(neigh);
-               read_unlock_bh(&neigh->lock);
-               r->arp_ha.sa_family = dev->type;
-               strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
+               if (!(neigh->nud_state & NUD_NOARP)) {
+                       read_lock_bh(&neigh->lock);
+                       memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
+                       r->arp_flags = arp_state_to_flags(neigh);
+                       read_unlock_bh(&neigh->lock);
+                       r->arp_ha.sa_family = dev->type;
+                       strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
+                       err = 0;
+               }
                neigh_release(neigh);
-               err = 0;
        }
        return err;
 }
index 90c0e8386116177f4bbf412f2175aec93c64870c..574fad9cca052cb2970e283a4dc5568c4b3b8b23 100644 (file)
@@ -20,7 +20,7 @@
 #include <net/route.h>
 #include <net/tcp_states.h>
 
-int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct inet_sock *inet = inet_sk(sk);
        struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
@@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        sk_dst_reset(sk);
 
-       lock_sock(sk);
-
        oif = sk->sk_bound_dev_if;
        saddr = inet->inet_saddr;
        if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
@@ -82,9 +80,19 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        sk_dst_set(sk, &rt->dst);
        err = 0;
 out:
-       release_sock(sk);
        return err;
 }
+EXPORT_SYMBOL(__ip4_datagram_connect);
+
+int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       int res;
+
+       lock_sock(sk);
+       res = __ip4_datagram_connect(sk, uaddr, addr_len);
+       release_sock(sk);
+       return res;
+}
 EXPORT_SYMBOL(ip4_datagram_connect);
 
 /* Because UDP xmit path can manipulate sk_dst_cache without holding
index 7498716e8f541b5a55aef59a85e70b302ba7248c..2d9cb1748f8191c785567632faf0ee14eaca628b 100644 (file)
@@ -882,7 +882,6 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
                queue_delayed_work(system_power_efficient_wq,
                                &check_lifetime_work, 0);
                rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
-               blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
        }
        return 0;
 }
@@ -1740,6 +1739,8 @@ static int inet_netconf_msgsize_devconf(int type)
                size += nla_total_size(4);
        if (type == -1 || type == NETCONFA_PROXY_NEIGH)
                size += nla_total_size(4);
+       if (type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
+               size += nla_total_size(4);
 
        return size;
 }
@@ -1780,6 +1781,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
            nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
                        IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
                goto nla_put_failure;
+       if ((type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
+           nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+                       IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
+               goto nla_put_failure;
 
        nlmsg_end(skb, nlh);
        return 0;
@@ -1819,6 +1824,7 @@ static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
        [NETCONFA_FORWARDING]   = { .len = sizeof(int) },
        [NETCONFA_RP_FILTER]    = { .len = sizeof(int) },
        [NETCONFA_PROXY_NEIGH]  = { .len = sizeof(int) },
+       [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]  = { .len = sizeof(int) },
 };
 
 static int inet_netconf_get_devconf(struct sk_buff *in_skb,
@@ -2048,6 +2054,12 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write,
                        inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
                                                    ifindex, cnf);
                }
+               if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 &&
+                   new_value != old_value) {
+                       ifindex = devinet_conf_ifindex(net, cnf);
+                       inet_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+                                                   ifindex, cnf);
+               }
        }
 
        return ret;
index c6211ed60b03be1940a1954c08adb8a265f4e124..9c02920725dbea00d2a4f84877e0769ff74cfe0c 100644 (file)
@@ -13,6 +13,7 @@ struct fib_alias {
        u8                      fa_state;
        u8                      fa_slen;
        u32                     tb_id;
+       s16                     fa_default;
        struct rcu_head         rcu;
 };
 
index c7358ea4ae93530a7f6ef110a2dc204f19ac830e..3a06586b170c0947ef62ecc08a5dcf1a1c768011 100644 (file)
@@ -1202,23 +1202,40 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event)
 }
 
 /* Must be invoked inside of an RCU protected region.  */
-void fib_select_default(struct fib_result *res)
+void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
 {
        struct fib_info *fi = NULL, *last_resort = NULL;
        struct hlist_head *fa_head = res->fa_head;
        struct fib_table *tb = res->table;
+       u8 slen = 32 - res->prefixlen;
        int order = -1, last_idx = -1;
-       struct fib_alias *fa;
+       struct fib_alias *fa, *fa1 = NULL;
+       u32 last_prio = res->fi->fib_priority;
+       u8 last_tos = 0;
 
        hlist_for_each_entry_rcu(fa, fa_head, fa_list) {
                struct fib_info *next_fi = fa->fa_info;
 
+               if (fa->fa_slen != slen)
+                       continue;
+               if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
+                       continue;
+               if (fa->tb_id != tb->tb_id)
+                       continue;
+               if (next_fi->fib_priority > last_prio &&
+                   fa->fa_tos == last_tos) {
+                       if (last_tos)
+                               continue;
+                       break;
+               }
+               if (next_fi->fib_flags & RTNH_F_DEAD)
+                       continue;
+               last_tos = fa->fa_tos;
+               last_prio = next_fi->fib_priority;
+
                if (next_fi->fib_scope != res->scope ||
                    fa->fa_type != RTN_UNICAST)
                        continue;
-
-               if (next_fi->fib_priority > res->fi->fib_priority)
-                       break;
                if (!next_fi->fib_nh[0].nh_gw ||
                    next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
                        continue;
@@ -1228,10 +1245,11 @@ void fib_select_default(struct fib_result *res)
                if (!fi) {
                        if (next_fi != res->fi)
                                break;
+                       fa1 = fa;
                } else if (!fib_detect_death(fi, order, &last_resort,
-                                            &last_idx, tb->tb_default)) {
+                                            &last_idx, fa1->fa_default)) {
                        fib_result_assign(res, fi);
-                       tb->tb_default = order;
+                       fa1->fa_default = order;
                        goto out;
                }
                fi = next_fi;
@@ -1239,20 +1257,21 @@ void fib_select_default(struct fib_result *res)
        }
 
        if (order <= 0 || !fi) {
-               tb->tb_default = -1;
+               if (fa1)
+                       fa1->fa_default = -1;
                goto out;
        }
 
        if (!fib_detect_death(fi, order, &last_resort, &last_idx,
-                               tb->tb_default)) {
+                             fa1->fa_default)) {
                fib_result_assign(res, fi);
-               tb->tb_default = order;
+               fa1->fa_default = order;
                goto out;
        }
 
        if (last_idx >= 0)
                fib_result_assign(res, last_resort);
-       tb->tb_default = last_idx;
+       fa1->fa_default = last_idx;
 out:
        return;
 }
index 15d32612e3c6f134a533034aa4d7f74fa52da51b..b0c6258ffb79a7cbcaaf1296e4842db52876b5b2 100644 (file)
@@ -1171,6 +1171,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
                        new_fa->fa_state = state & ~FA_S_ACCESSED;
                        new_fa->fa_slen = fa->fa_slen;
                        new_fa->tb_id = tb->tb_id;
+                       new_fa->fa_default = -1;
 
                        err = switchdev_fib_ipv4_add(key, plen, fi,
                                                     new_fa->fa_tos,
@@ -1222,6 +1223,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
        new_fa->fa_state = 0;
        new_fa->fa_slen = slen;
        new_fa->tb_id = tb->tb_id;
+       new_fa->fa_default = -1;
 
        /* (Optionally) offload fib entry to switch hardware. */
        err = switchdev_fib_ipv4_add(key, plen, fi, tos, cfg->fc_type,
@@ -1791,8 +1793,6 @@ void fib_table_flush_external(struct fib_table *tb)
                if (hlist_empty(&n->leaf)) {
                        put_child_root(pn, n->key, NULL);
                        node_free(n);
-               } else {
-                       leaf_pull_suffix(pn, n);
                }
        }
 }
@@ -1862,8 +1862,6 @@ int fib_table_flush(struct fib_table *tb)
                if (hlist_empty(&n->leaf)) {
                        put_child_root(pn, n->key, NULL);
                        node_free(n);
-               } else {
-                       leaf_pull_suffix(pn, n);
                }
        }
 
@@ -1990,7 +1988,6 @@ struct fib_table *fib_trie_table(u32 id, struct fib_table *alias)
                return NULL;
 
        tb->tb_id = id;
-       tb->tb_default = -1;
        tb->tb_num_default = 0;
        tb->tb_data = (alias ? alias->__data : tb->__data);
 
@@ -2468,7 +2465,7 @@ static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter,
                key = l->key + 1;
                iter->pos++;
 
-               if (pos-- <= 0)
+               if (--pos <= 0)
                        break;
 
                l = NULL;
index 651cdf648ec4728bff6e709b0324b7d52ffd65ed..9fdfd9deac11dde85bc62803068fbe50e45837b8 100644 (file)
@@ -1435,33 +1435,35 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
        struct sk_buff *skb_chk;
        unsigned int transport_len;
        unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
-       int ret;
+       int ret = -EINVAL;
 
        transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
 
-       skb_get(skb);
        skb_chk = skb_checksum_trimmed(skb, transport_len,
                                       ip_mc_validate_checksum);
        if (!skb_chk)
-               return -EINVAL;
+               goto err;
 
-       if (!pskb_may_pull(skb_chk, len)) {
-               kfree_skb(skb_chk);
-               return -EINVAL;
-       }
+       if (!pskb_may_pull(skb_chk, len))
+               goto err;
 
        ret = ip_mc_check_igmp_msg(skb_chk);
-       if (ret) {
-               kfree_skb(skb_chk);
-               return ret;
-       }
+       if (ret)
+               goto err;
 
        if (skb_trimmed)
                *skb_trimmed = skb_chk;
-       else
+       /* free now unneeded clone */
+       else if (skb_chk != skb)
                kfree_skb(skb_chk);
 
-       return 0;
+       ret = 0;
+
+err:
+       if (ret && skb_chk && skb_chk != skb)
+               kfree_skb(skb_chk);
+
+       return ret;
 }
 
 /**
@@ -1470,7 +1472,7 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
  * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
  *
  * Checks whether an IPv4 packet is a valid IGMP packet. If so sets
- * skb network and transport headers accordingly and returns zero.
+ * skb transport header accordingly and returns zero.
  *
  * -EINVAL: A broken packet was detected, i.e. it violates some internet
  *  standard
@@ -1485,7 +1487,8 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
  * to leave the original skb and its full frame unchanged (which might be
  * desirable for layer 2 frame jugglers).
  *
- * The caller needs to release a reference count from any returned skb_trimmed.
+ * Caller needs to set the skb network header and free any returned skb if it
+ * differs from the provided skb.
  */
 int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
 {
index 60021d0d9326ac691dcef21e1f9c20de5f8fe7c6..134957159c27eb9180e08b73360fe891574b4742 100644 (file)
@@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue,
        }
 
        spin_unlock(&queue->syn_wait_lock);
-       if (del_timer(&req->rsk_timer))
+       if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer))
                reqsk_put(req);
        return found;
 }
index 9bc26677058e0420739e4a7bcb7ffd1b593d6e67..c3b1f3a0f4cf63df6c7e862f96e44c8653d3a476 100644 (file)
@@ -152,8 +152,8 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                                       inet6_sk(sk)->tclass) < 0)
                                goto errout;
 
-               if (ipv6_only_sock(sk) &&
-                   nla_put_u8(skb, INET_DIAG_SKV6ONLY, 1))
+               if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
+                   nla_put_u8(skb, INET_DIAG_SKV6ONLY, ipv6_only_sock(sk)))
                        goto errout;
        }
 #endif
index 5e346a082e5ff05b58cfebb64917ee26001d809d..d0a7c0319e3d1b1b73f828717062b6fbbd3be27d 100644 (file)
@@ -131,34 +131,22 @@ inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb)
        unsigned int evicted = 0;
        HLIST_HEAD(expired);
 
-evict_again:
        spin_lock(&hb->chain_lock);
 
        hlist_for_each_entry_safe(fq, n, &hb->chain, list) {
                if (!inet_fragq_should_evict(fq))
                        continue;
 
-               if (!del_timer(&fq->timer)) {
-                       /* q expiring right now thus increment its refcount so
-                        * it won't be freed under us and wait until the timer
-                        * has finished executing then destroy it
-                        */
-                       atomic_inc(&fq->refcnt);
-                       spin_unlock(&hb->chain_lock);
-                       del_timer_sync(&fq->timer);
-                       inet_frag_put(fq, f);
-                       goto evict_again;
-               }
+               if (!del_timer(&fq->timer))
+                       continue;
 
-               fq->flags |= INET_FRAG_EVICTED;
-               hlist_del(&fq->list);
-               hlist_add_head(&fq->list, &expired);
+               hlist_add_head(&fq->list_evictor, &expired);
                ++evicted;
        }
 
        spin_unlock(&hb->chain_lock);
 
-       hlist_for_each_entry_safe(fq, n, &expired, list)
+       hlist_for_each_entry_safe(fq, n, &expired, list_evictor)
                f->frag_expire((unsigned long) fq);
 
        return evicted;
@@ -240,18 +228,20 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f)
        int i;
 
        nf->low_thresh = 0;
-       local_bh_disable();
 
 evict_again:
+       local_bh_disable();
        seq = read_seqbegin(&f->rnd_seqlock);
 
        for (i = 0; i < INETFRAGS_HASHSZ ; i++)
                inet_evict_bucket(f, &f->hash[i]);
 
-       if (read_seqretry(&f->rnd_seqlock, seq))
-               goto evict_again;
-
        local_bh_enable();
+       cond_resched();
+
+       if (read_seqretry(&f->rnd_seqlock, seq) ||
+           percpu_counter_sum(&nf->mem))
+               goto evict_again;
 
        percpu_counter_destroy(&nf->mem);
 }
@@ -284,8 +274,8 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
        struct inet_frag_bucket *hb;
 
        hb = get_frag_bucket_locked(fq, f);
-       if (!(fq->flags & INET_FRAG_EVICTED))
-               hlist_del(&fq->list);
+       hlist_del(&fq->list);
+       fq->flags |= INET_FRAG_COMPLETE;
        spin_unlock(&hb->chain_lock);
 }
 
@@ -297,7 +287,6 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
        if (!(fq->flags & INET_FRAG_COMPLETE)) {
                fq_unlink(fq, f);
                atomic_dec(&fq->refcnt);
-               fq->flags |= INET_FRAG_COMPLETE;
        }
 }
 EXPORT_SYMBOL(inet_frag_kill);
@@ -330,11 +319,12 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f)
                fp = xp;
        }
        sum = sum_truesize + f->qsize;
-       sub_frag_mem_limit(q, sum);
 
        if (f->destructor)
                f->destructor(q);
        kmem_cache_free(f->frags_cachep, q);
+
+       sub_frag_mem_limit(nf, sum);
 }
 EXPORT_SYMBOL(inet_frag_destroy);
 
@@ -390,7 +380,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
 
        q->net = nf;
        f->constructor(q, arg);
-       add_frag_mem_limit(q, f->qsize);
+       add_frag_mem_limit(nf, f->qsize);
 
        setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
        spin_lock_init(&q->lock);
index 5f9b063bbe8ab4f3755a5711ae19b816a3bc2026..0cb9165421d450ae8f6aff81b88ef4bf2839ff51 100644 (file)
@@ -624,22 +624,21 @@ EXPORT_SYMBOL_GPL(inet_hashinfo_init);
 
 int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo)
 {
+       unsigned int locksz = sizeof(spinlock_t);
        unsigned int i, nblocks = 1;
 
-       if (sizeof(spinlock_t) != 0) {
+       if (locksz != 0) {
                /* allocate 2 cache lines or at least one spinlock per cpu */
-               nblocks = max_t(unsigned int,
-                               2 * L1_CACHE_BYTES / sizeof(spinlock_t),
-                               1);
+               nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U);
                nblocks = roundup_pow_of_two(nblocks * num_possible_cpus());
 
                /* no more locks than number of hash buckets */
                nblocks = min(nblocks, hashinfo->ehash_mask + 1);
 
-               hashinfo->ehash_locks = kmalloc_array(nblocks, sizeof(spinlock_t),
+               hashinfo->ehash_locks = kmalloc_array(nblocks, locksz,
                                                      GFP_KERNEL | __GFP_NOWARN);
                if (!hashinfo->ehash_locks)
-                       hashinfo->ehash_locks = vmalloc(nblocks * sizeof(spinlock_t));
+                       hashinfo->ehash_locks = vmalloc(nblocks * locksz);
 
                if (!hashinfo->ehash_locks)
                        return -ENOMEM;
index a50dc6d408d11c339b38f2436216c8568c4149cf..921138f6c97c9948a7cf5e2e36b7e3dbfabc6e29 100644 (file)
@@ -202,7 +202,7 @@ static void ip_expire(unsigned long arg)
        ipq_kill(qp);
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
 
-       if (!(qp->q.flags & INET_FRAG_EVICTED)) {
+       if (!inet_frag_evicting(&qp->q)) {
                struct sk_buff *head = qp->q.fragments;
                const struct iphdr *iph;
                int err;
@@ -309,7 +309,7 @@ static int ip_frag_reinit(struct ipq *qp)
                kfree_skb(fp);
                fp = xp;
        } while (fp);
-       sub_frag_mem_limit(&qp->q, sum_truesize);
+       sub_frag_mem_limit(qp->q.net, sum_truesize);
 
        qp->q.flags = 0;
        qp->q.len = 0;
@@ -351,7 +351,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
        ihl = ip_hdrlen(skb);
 
        /* Determine the position of this fragment. */
-       end = offset + skb->len - ihl;
+       end = offset + skb->len - skb_network_offset(skb) - ihl;
        err = -EINVAL;
 
        /* Is this the final fragment? */
@@ -381,7 +381,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
                goto err;
 
        err = -ENOMEM;
-       if (!pskb_pull(skb, ihl))
+       if (!pskb_pull(skb, skb_network_offset(skb) + ihl))
                goto err;
 
        err = pskb_trim_rcsum(skb, end - offset);
@@ -455,7 +455,7 @@ found:
                                qp->q.fragments = next;
 
                        qp->q.meat -= free_it->len;
-                       sub_frag_mem_limit(&qp->q, free_it->truesize);
+                       sub_frag_mem_limit(qp->q.net, free_it->truesize);
                        kfree_skb(free_it);
                }
        }
@@ -479,7 +479,7 @@ found:
        qp->q.stamp = skb->tstamp;
        qp->q.meat += skb->len;
        qp->ecn |= ecn;
-       add_frag_mem_limit(&qp->q, skb->truesize);
+       add_frag_mem_limit(qp->q.net, skb->truesize);
        if (offset == 0)
                qp->q.flags |= INET_FRAG_FIRST_IN;
 
@@ -587,7 +587,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               add_frag_mem_limit(&qp->q, clone->truesize);
+               add_frag_mem_limit(qp->q.net, clone->truesize);
        }
 
        skb_push(head, head->data - skb_network_header(head));
@@ -615,7 +615,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&qp->q, sum_truesize);
+       sub_frag_mem_limit(qp->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
@@ -641,6 +641,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                iph->frag_off = 0;
        }
 
+       ip_send_check(iph);
+
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
        qp->q.fragments = NULL;
        qp->q.fragments_tail = NULL;
index 4c2c3ba4ba6595c788940e3ec2c2dadfe7abe2f0..626d9e56a6bd2671611f3dde4f8090b76645301c 100644 (file)
@@ -586,7 +586,8 @@ int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
 EXPORT_SYMBOL(ip_tunnel_encap);
 
 static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
-                           struct rtable *rt, __be16 df)
+                           struct rtable *rt, __be16 df,
+                           const struct iphdr *inner_iph)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len;
@@ -603,7 +604,8 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
 
        if (skb->protocol == htons(ETH_P_IP)) {
                if (!skb_is_gso(skb) &&
-                   (df & htons(IP_DF)) && mtu < pkt_size) {
+                   (inner_iph->frag_off & htons(IP_DF)) &&
+                   mtu < pkt_size) {
                        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
                        return -E2BIG;
@@ -737,7 +739,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                goto tx_error;
        }
 
-       if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off)) {
+       if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph)) {
                ip_rt_put(rt);
                goto tx_error;
        }
index 95c9b6eece25dfa8da28f8866dd7e55ec86b72e7..92305a1a021a7936206f9078008532bc151ec757 100644 (file)
@@ -254,9 +254,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
        unsigned int verdict = NF_DROP;
        const struct arphdr *arp;
-       struct arpt_entry *e, *back;
+       struct arpt_entry *e, **jumpstack;
        const char *indev, *outdev;
        const void *table_base;
+       unsigned int cpu, stackidx = 0;
        const struct xt_table_info *private;
        struct xt_action_param acpar;
        unsigned int addend;
@@ -270,15 +271,16 @@ unsigned int arpt_do_table(struct sk_buff *skb,
        local_bh_disable();
        addend = xt_write_recseq_begin();
        private = table->private;
+       cpu     = smp_processor_id();
        /*
         * Ensure we load private-> members after we've fetched the base
         * pointer.
         */
        smp_read_barrier_depends();
        table_base = private->entries;
+       jumpstack  = (struct arpt_entry **)private->jumpstack[cpu];
 
        e = get_entry(table_base, private->hook_entry[hook]);
-       back = get_entry(table_base, private->underflow[hook]);
 
        acpar.in      = state->in;
        acpar.out     = state->out;
@@ -312,18 +314,23 @@ unsigned int arpt_do_table(struct sk_buff *skb,
                                        verdict = (unsigned int)(-v) - 1;
                                        break;
                                }
-                               e = back;
-                               back = get_entry(table_base, back->comefrom);
+                               if (stackidx == 0) {
+                                       e = get_entry(table_base,
+                                                     private->underflow[hook]);
+                               } else {
+                                       e = jumpstack[--stackidx];
+                                       e = arpt_next_entry(e);
+                               }
                                continue;
                        }
                        if (table_base + v
                            != arpt_next_entry(e)) {
-                               /* Save old back ptr in next entry */
-                               struct arpt_entry *next = arpt_next_entry(e);
-                               next->comefrom = (void *)back - table_base;
 
-                               /* set back pointer to next entry */
-                               back = next;
+                               if (stackidx >= private->stacksize) {
+                                       verdict = NF_DROP;
+                                       break;
+                               }
+                               jumpstack[stackidx++] = e;
                        }
 
                        e = get_entry(table_base, v);
index fe8cc183411e052f6e0ba4afefbeaef1e77313cd..95ea633e8356eb9b419e4027f9954810194aa23c 100644 (file)
@@ -226,7 +226,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+       synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+                         niph, nth, tcp_hdr_size);
 }
 
 static bool
index d0362a2de3d3805260c878f5e3a9341e225cade9..e681b852ced1d0c0cde984496d832d9cf3f7fad2 100644 (file)
@@ -2176,7 +2176,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
        if (!res.prefixlen &&
            res.table->tb_num_default > 1 &&
            res.type == RTN_UNICAST && !fl4->flowi4_oif)
-               fib_select_default(&res);
+               fib_select_default(fl4, &res);
 
        if (!fl4->saddr)
                fl4->saddr = FIB_RES_PREFSRC(net, res);
index 433231ccfb17fc6d01179247d1d81226803d18df..0330ab2e2b6329ced120cd9b7100a5a34f50e82b 100644 (file)
@@ -41,8 +41,6 @@ static int tcp_syn_retries_min = 1;
 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 };
-static int min_sndbuf = SOCK_MIN_SNDBUF;
-static int min_rcvbuf = SOCK_MIN_RCVBUF;
 
 /* Update system visible IP port range */
 static void set_local_port_range(struct net *net, int range[2])
@@ -530,7 +528,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(sysctl_tcp_wmem),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &min_sndbuf,
+               .extra1         = &one,
        },
        {
                .procname       = "tcp_notsent_lowat",
@@ -545,7 +543,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(sysctl_tcp_rmem),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &min_rcvbuf,
+               .extra1         = &one,
        },
        {
                .procname       = "tcp_app_win",
@@ -758,7 +756,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(sysctl_udp_rmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &min_rcvbuf,
+               .extra1         = &one
        },
        {
                .procname       = "udp_wmem_min",
@@ -766,7 +764,7 @@ static struct ctl_table ipv4_table[] = {
                .maxlen         = sizeof(sysctl_udp_wmem_min),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &min_sndbuf,
+               .extra1         = &one
        },
        { }
 };
index 7f4056785accb76eec60e22dc0bb19febc98f75f..45534a5ab43065307bfe2708a5ae08936cc5969a 100644 (file)
@@ -780,7 +780,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
                                ret = -EAGAIN;
                                break;
                        }
-                       sk_wait_data(sk, &timeo);
+                       sk_wait_data(sk, &timeo, NULL);
                        if (signal_pending(current)) {
                                ret = sock_intr_errno(timeo);
                                break;
@@ -1575,7 +1575,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
        int target;             /* Read at least this many bytes */
        long timeo;
        struct task_struct *user_recv = NULL;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *last;
        u32 urg_hole = 0;
 
        if (unlikely(flags & MSG_ERRQUEUE))
@@ -1635,7 +1635,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
 
                /* Next get a buffer. */
 
+               last = skb_peek_tail(&sk->sk_receive_queue);
                skb_queue_walk(&sk->sk_receive_queue, skb) {
+                       last = skb;
                        /* Now that we have two receive queues this
                         * shouldn't happen.
                         */
@@ -1754,8 +1756,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
                        /* Do not sleep, just process backlog. */
                        release_sock(sk);
                        lock_sock(sk);
-               } else
-                       sk_wait_data(sk, &timeo);
+               } else {
+                       sk_wait_data(sk, &timeo, last);
+               }
 
                if (user_recv) {
                        int chunk;
index 684f095d196e20333adb235fc96a8fb8f0dd691c..728f5b3d3c64197bb526240a078744d5a950c8ea 100644 (file)
@@ -1917,14 +1917,13 @@ void tcp_enter_loss(struct sock *sk)
        const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
-       bool new_recovery = false;
+       bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery;
        bool is_reneg;                  /* is receiver reneging on SACKs? */
 
        /* Reduce ssthresh if it has not yet been made inside this window. */
        if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
            !after(tp->high_seq, tp->snd_una) ||
            (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
-               new_recovery = true;
                tp->prior_ssthresh = tcp_current_ssthresh(sk);
                tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
                tcp_ca_event(sk, CA_EVENT_LOSS);
index d7d4c2b79cf2f516f9e3f62c6fe4415e9bc137a0..0ea2e1c5d395ac979e9a301d006867d49b866ecb 100644 (file)
@@ -1348,7 +1348,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
        if (req) {
                nsk = tcp_check_req(sk, skb, req, false);
-               if (!nsk)
+               if (!nsk || nsk == sk)
                        reqsk_put(req);
                return nsk;
        }
index 83aa604f9273c332c5a0e5399253d961ef92eb9a..1b8c5ba7d5f732ea2220ada929049c5c7cfd5e83 100644 (file)
@@ -1995,12 +1995,19 @@ void udp_v4_early_demux(struct sk_buff *skb)
 
        skb->sk = sk;
        skb->destructor = sock_efree;
-       dst = sk->sk_rx_dst;
+       dst = READ_ONCE(sk->sk_rx_dst);
 
        if (dst)
                dst = dst_check(dst, 0);
-       if (dst)
-               skb_dst_set_noref(skb, dst);
+       if (dst) {
+               /* DST_NOCACHE can not be used without taking a reference */
+               if (dst->flags & DST_NOCACHE) {
+                       if (likely(atomic_inc_not_zero(&dst->__refcnt)))
+                               skb_dst_set(skb, dst);
+               } else {
+                       skb_dst_set_noref(skb, dst);
+               }
+       }
 }
 
 int udp_rcv(struct sk_buff *skb)
index 62d908e64eeb53740d53ddfd57e26867c4e7e4d3..b10a88986a9896a4a33f8a4139e41d3f1013a41a 100644 (file)
@@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
        return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0);
 }
 
-int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
        struct inet_sock        *inet = inet_sk(sk);
@@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (usin->sin6_family == AF_INET) {
                if (__ipv6_only_sock(sk))
                        return -EAFNOSUPPORT;
-               err = ip4_datagram_connect(sk, uaddr, addr_len);
+               err = __ip4_datagram_connect(sk, uaddr, addr_len);
                goto ipv4_connected;
        }
 
@@ -98,9 +98,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
                sin.sin_port = usin->sin6_port;
 
-               err = ip4_datagram_connect(sk,
-                                          (struct sockaddr *) &sin,
-                                          sizeof(sin));
+               err = __ip4_datagram_connect(sk,
+                                            (struct sockaddr *) &sin,
+                                            sizeof(sin));
 
 ipv4_connected:
                if (err)
@@ -204,6 +204,16 @@ out:
        fl6_sock_release(flowlabel);
        return err;
 }
+
+int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       int res;
+
+       lock_sock(sk);
+       res = __ip6_datagram_connect(sk, uaddr, addr_len);
+       release_sock(sk);
+       return res;
+}
 EXPORT_SYMBOL_GPL(ip6_datagram_connect);
 
 int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr,
index 55d19861ab20f4a91b6b289be7ca3b0250df4531..548c6237b1e706f8ef72575a6a7dbad544b60fcc 100644 (file)
@@ -172,6 +172,8 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt)
                        *ppcpu_rt = NULL;
                }
        }
+
+       non_pcpu_rt->rt6i_pcpu = NULL;
 }
 
 static void rt6_release(struct rt6_info *rt)
index f2e464eba5efdb7b2a8abe3c2cecedae473777e7..57990c929cd8156ebac52c648deb50fd3f74ab82 100644 (file)
@@ -331,10 +331,10 @@ int ip6_mc_input(struct sk_buff *skb)
                                if (offset < 0)
                                        goto out;
 
-                               if (!ipv6_is_mld(skb, nexthdr, offset))
-                                       goto out;
+                               if (ipv6_is_mld(skb, nexthdr, offset))
+                                       deliver = true;
 
-                               deliver = true;
+                               goto out;
                        }
                        /* unknown RA - process it normally */
                }
index e893cd18612fcdc9e8577f0e060ffd32b5659eea..08b62047c67f311ca808533cb7a83b5caab0cfc8 100644 (file)
@@ -292,8 +292,6 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
 static const struct net_offload sit_offload = {
        .callbacks = {
                .gso_segment    = ipv6_gso_segment,
-               .gro_receive    = ipv6_gro_receive,
-               .gro_complete   = ipv6_gro_complete,
        },
 };
 
index df8afe5ab31e4b8e75bf2fbf844f8b3e798edbba..9405b04eecc64f478960329da93f6e01d437954e 100644 (file)
@@ -143,34 +143,36 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
        struct sk_buff *skb_chk = NULL;
        unsigned int transport_len;
        unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
-       int ret;
+       int ret = -EINVAL;
 
        transport_len = ntohs(ipv6_hdr(skb)->payload_len);
        transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr);
 
-       skb_get(skb);
        skb_chk = skb_checksum_trimmed(skb, transport_len,
                                       ipv6_mc_validate_checksum);
        if (!skb_chk)
-               return -EINVAL;
+               goto err;
 
-       if (!pskb_may_pull(skb_chk, len)) {
-               kfree_skb(skb_chk);
-               return -EINVAL;
-       }
+       if (!pskb_may_pull(skb_chk, len))
+               goto err;
 
        ret = ipv6_mc_check_mld_msg(skb_chk);
-       if (ret) {
-               kfree_skb(skb_chk);
-               return ret;
-       }
+       if (ret)
+               goto err;
 
        if (skb_trimmed)
                *skb_trimmed = skb_chk;
-       else
+       /* free now unneeded clone */
+       else if (skb_chk != skb)
                kfree_skb(skb_chk);
 
-       return 0;
+       ret = 0;
+
+err:
+       if (ret && skb_chk && skb_chk != skb)
+               kfree_skb(skb_chk);
+
+       return ret;
 }
 
 /**
@@ -179,7 +181,7 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
  * @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional)
  *
  * Checks whether an IPv6 packet is a valid MLD packet. If so sets
- * skb network and transport headers accordingly and returns zero.
+ * skb transport header accordingly and returns zero.
  *
  * -EINVAL: A broken packet was detected, i.e. it violates some internet
  *  standard
@@ -194,7 +196,8 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
  * to leave the original skb and its full frame unchanged (which might be
  * desirable for layer 2 frame jugglers).
  *
- * The caller needs to release a reference count from any returned skb_trimmed.
+ * Caller needs to set the skb network header and free any returned skb if it
+ * differs from the provided skb.
  */
 int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed)
 {
index 0a05b35a90fc946dc0de3ae76e4a682ca4438932..c53331cfed95dcbb6672b80282125516e904a84f 100644 (file)
@@ -1650,6 +1650,7 @@ int ndisc_rcv(struct sk_buff *skb)
 static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct netdev_notifier_change_info *change_info;
        struct net *net = dev_net(dev);
        struct inet6_dev *idev;
 
@@ -1664,6 +1665,11 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
                        ndisc_send_unsol_na(dev);
                in6_dev_put(idev);
                break;
+       case NETDEV_CHANGE:
+               change_info = ptr;
+               if (change_info->flags_changed & IFF_NOARP)
+                       neigh_changeaddr(&nd_tbl, dev);
+               break;
        case NETDEV_DOWN:
                neigh_ifdown(&nd_tbl, dev);
                fib6_run_gc(0, net, false);
index 6edb7b106de769728357174d0657c644f83e41e8..ebbb754c2111b73c87fe85aa58b3124e0a3032ef 100644 (file)
@@ -37,12 +37,13 @@ synproxy_build_ip(struct sk_buff *skb, const struct in6_addr *saddr,
 }
 
 static void
-synproxy_send_tcp(const struct sk_buff *skb, struct sk_buff *nskb,
+synproxy_send_tcp(const struct synproxy_net *snet,
+                 const struct sk_buff *skb, struct sk_buff *nskb,
                  struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
                  struct ipv6hdr *niph, struct tcphdr *nth,
                  unsigned int tcp_hdr_size)
 {
-       struct net *net = nf_ct_net((struct nf_conn *)nfct);
+       struct net *net = nf_ct_net(snet->tmpl);
        struct dst_entry *dst;
        struct flowi6 fl6;
 
@@ -83,7 +84,8 @@ free_nskb:
 }
 
 static void
-synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th,
+synproxy_send_client_synack(const struct synproxy_net *snet,
+                           const struct sk_buff *skb, const struct tcphdr *th,
                            const struct synproxy_options *opts)
 {
        struct sk_buff *nskb;
@@ -119,7 +121,7 @@ synproxy_send_client_synack(const struct sk_buff *skb, const struct tcphdr *th,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+       synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
                          niph, nth, tcp_hdr_size);
 }
 
@@ -163,7 +165,7 @@ synproxy_send_server_syn(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
+       synproxy_send_tcp(snet, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
                          niph, nth, tcp_hdr_size);
 }
 
@@ -203,7 +205,7 @@ synproxy_send_server_ack(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+       synproxy_send_tcp(snet, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
 }
 
 static void
@@ -241,7 +243,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
 
        synproxy_build_options(nth, opts);
 
-       synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
+       synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
+                         niph, nth, tcp_hdr_size);
 }
 
 static bool
@@ -301,7 +304,7 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par)
                                          XT_SYNPROXY_OPT_SACK_PERM |
                                          XT_SYNPROXY_OPT_ECN);
 
-               synproxy_send_client_synack(skb, th, &opts);
+               synproxy_send_client_synack(snet, skb, th, &opts);
                return NF_DROP;
 
        } else if (th->ack && !(th->fin || th->rst || th->syn)) {
index 6f187c8d8a1bdf4ab27ec71ea05e865fcf782371..6d02498172c168f2716e3b71a29e3b082a93dcfb 100644 (file)
@@ -348,7 +348,7 @@ found:
        fq->ecn |= ecn;
        if (payload_len > fq->q.max_size)
                fq->q.max_size = payload_len;
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -430,7 +430,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
                clone->ip_summed = head->ip_summed;
 
                NFCT_FRAG6_CB(clone)->orig = NULL;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -454,7 +454,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
                        head->csum = csum_add(head->csum, fp->csum);
                head->truesize += fp->truesize;
        }
-       sub_frag_mem_limit(&fq->q, head->truesize);
+       sub_frag_mem_limit(fq->q.net, head->truesize);
 
        head->ignore_df = 1;
        head->next = NULL;
index 8ffa2c8cce774e8398a031ab90c69a3ed2934a6a..f1159bb76e0a54fb55a3e8e382a6cb80c7a929f9 100644 (file)
@@ -144,7 +144,7 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
 
-       if (fq->q.flags & INET_FRAG_EVICTED)
+       if (inet_frag_evicting(&fq->q))
                goto out_rcu_unlock;
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
@@ -330,7 +330,7 @@ found:
        fq->q.stamp = skb->tstamp;
        fq->q.meat += skb->len;
        fq->ecn |= ecn;
-       add_frag_mem_limit(&fq->q, skb->truesize);
+       add_frag_mem_limit(fq->q.net, skb->truesize);
 
        /* The first fragment.
         * nhoffset is obtained from the first fragment, of course.
@@ -443,7 +443,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
-               add_frag_mem_limit(&fq->q, clone->truesize);
+               add_frag_mem_limit(fq->q.net, clone->truesize);
        }
 
        /* We have to remove fragment header from datagram and to relocate
@@ -481,7 +481,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                }
                fp = next;
        }
-       sub_frag_mem_limit(&fq->q, sum_truesize);
+       sub_frag_mem_limit(fq->q.net, sum_truesize);
 
        head->next = NULL;
        head->dev = dev;
index 1a1122a6bbf5208481f81f1e2643cbc41ed2e7e9..d15586490cecaedcc29bc821163cd6c85544b0b8 100644 (file)
@@ -318,8 +318,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = {
 /* allocate dst with ip6_dst_ops */
 static struct rt6_info *__ip6_dst_alloc(struct net *net,
                                        struct net_device *dev,
-                                       int flags,
-                                       struct fib6_table *table)
+                                       int flags)
 {
        struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
                                        0, DST_OBSOLETE_FORCE_CHK, flags);
@@ -336,10 +335,9 @@ static struct rt6_info *__ip6_dst_alloc(struct net *net,
 
 static struct rt6_info *ip6_dst_alloc(struct net *net,
                                      struct net_device *dev,
-                                     int flags,
-                                     struct fib6_table *table)
+                                     int flags)
 {
-       struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags, table);
+       struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
 
        if (rt) {
                rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
@@ -369,10 +367,7 @@ static void ip6_dst_destroy(struct dst_entry *dst)
        struct inet6_dev *idev;
 
        dst_destroy_metrics_generic(dst);
-
-       if (rt->rt6i_pcpu)
-               free_percpu(rt->rt6i_pcpu);
-
+       free_percpu(rt->rt6i_pcpu);
        rt6_uncached_list_del(rt);
 
        idev = rt->rt6i_idev;
@@ -953,8 +948,7 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
        if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
                ort = (struct rt6_info *)ort->dst.from;
 
-       rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev,
-                            0, ort->rt6i_table);
+       rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0);
 
        if (!rt)
                return NULL;
@@ -986,8 +980,7 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
        struct rt6_info *pcpu_rt;
 
        pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev),
-                                 rt->dst.dev, rt->dst.flags,
-                                 rt->rt6i_table);
+                                 rt->dst.dev, rt->dst.flags);
 
        if (!pcpu_rt)
                return NULL;
@@ -1000,32 +993,53 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt)
 /* It should be called with read_lock_bh(&tb6_lock) acquired */
 static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
 {
-       struct rt6_info *pcpu_rt, *prev, **p;
+       struct rt6_info *pcpu_rt, **p;
 
        p = this_cpu_ptr(rt->rt6i_pcpu);
        pcpu_rt = *p;
 
-       if (pcpu_rt)
-               goto done;
+       if (pcpu_rt) {
+               dst_hold(&pcpu_rt->dst);
+               rt6_dst_from_metrics_check(pcpu_rt);
+       }
+       return pcpu_rt;
+}
+
+static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt)
+{
+       struct fib6_table *table = rt->rt6i_table;
+       struct rt6_info *pcpu_rt, *prev, **p;
 
        pcpu_rt = ip6_rt_pcpu_alloc(rt);
        if (!pcpu_rt) {
                struct net *net = dev_net(rt->dst.dev);
 
-               pcpu_rt = net->ipv6.ip6_null_entry;
-               goto done;
+               dst_hold(&net->ipv6.ip6_null_entry->dst);
+               return net->ipv6.ip6_null_entry;
        }
 
-       prev = cmpxchg(p, NULL, pcpu_rt);
-       if (prev) {
-               /* If someone did it before us, return prev instead */
+       read_lock_bh(&table->tb6_lock);
+       if (rt->rt6i_pcpu) {
+               p = this_cpu_ptr(rt->rt6i_pcpu);
+               prev = cmpxchg(p, NULL, pcpu_rt);
+               if (prev) {
+                       /* If someone did it before us, return prev instead */
+                       dst_destroy(&pcpu_rt->dst);
+                       pcpu_rt = prev;
+               }
+       } else {
+               /* rt has been removed from the fib6 tree
+                * before we have a chance to acquire the read_lock.
+                * In this case, don't brother to create a pcpu rt
+                * since rt is going away anyway.  The next
+                * dst_check() will trigger a re-lookup.
+                */
                dst_destroy(&pcpu_rt->dst);
-               pcpu_rt = prev;
+               pcpu_rt = rt;
        }
-
-done:
        dst_hold(&pcpu_rt->dst);
        rt6_dst_from_metrics_check(pcpu_rt);
+       read_unlock_bh(&table->tb6_lock);
        return pcpu_rt;
 }
 
@@ -1100,9 +1114,22 @@ redo_rt6_select:
                rt->dst.lastuse = jiffies;
                rt->dst.__use++;
                pcpu_rt = rt6_get_pcpu_route(rt);
-               read_unlock_bh(&table->tb6_lock);
+
+               if (pcpu_rt) {
+                       read_unlock_bh(&table->tb6_lock);
+               } else {
+                       /* We have to do the read_unlock first
+                        * because rt6_make_pcpu_route() may trigger
+                        * ip6_dst_gc() which will take the write_lock.
+                        */
+                       dst_hold(&rt->dst);
+                       read_unlock_bh(&table->tb6_lock);
+                       pcpu_rt = rt6_make_pcpu_route(rt);
+                       dst_release(&rt->dst);
+               }
 
                return pcpu_rt;
+
        }
 }
 
@@ -1558,7 +1585,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
        if (unlikely(!idev))
                return ERR_PTR(-ENODEV);
 
-       rt = ip6_dst_alloc(net, dev, 0, NULL);
+       rt = ip6_dst_alloc(net, dev, 0);
        if (unlikely(!rt)) {
                in6_dev_put(idev);
                dst = ERR_PTR(-ENOMEM);
@@ -1745,7 +1772,8 @@ int ip6_route_add(struct fib6_config *cfg)
        if (!table)
                goto out;
 
-       rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
+       rt = ip6_dst_alloc(net, NULL,
+                          (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT);
 
        if (!rt) {
                err = -ENOMEM;
@@ -1834,6 +1862,7 @@ int ip6_route_add(struct fib6_config *cfg)
                int gwa_type;
 
                gw_addr = &cfg->fc_gateway;
+               gwa_type = ipv6_addr_type(gw_addr);
 
                /* if gw_addr is local we will fail to detect this in case
                 * address is still TENTATIVE (DAD in progress). rt6_lookup()
@@ -1841,11 +1870,12 @@ int ip6_route_add(struct fib6_config *cfg)
                 * prefix route was assigned to, which might be non-loopback.
                 */
                err = -EINVAL;
-               if (ipv6_chk_addr_and_flags(net, gw_addr, NULL, 0, 0))
+               if (ipv6_chk_addr_and_flags(net, gw_addr,
+                                           gwa_type & IPV6_ADDR_LINKLOCAL ?
+                                           dev : NULL, 0, 0))
                        goto out;
 
                rt->rt6i_gateway = *gw_addr;
-               gwa_type = ipv6_addr_type(gw_addr);
 
                if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
                        struct rt6_info *grt;
@@ -2400,7 +2430,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 {
        struct net *net = dev_net(idev->dev);
        struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev,
-                                           DST_NOCOUNT, NULL);
+                                           DST_NOCOUNT);
        if (!rt)
                return ERR_PTR(-ENOMEM);
 
index 6748c4277affad71cd721e3a985af10c31c047ad..7a6cea5e427414062f408cfa66f57808d48382d7 100644 (file)
@@ -943,7 +943,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
                                   &ipv6_hdr(skb)->daddr, tcp_v6_iif(skb));
        if (req) {
                nsk = tcp_check_req(sk, skb, req, false);
-               if (!nsk)
+               if (!nsk || nsk == sk)
                        reqsk_put(req);
                return nsk;
        }
index 8fd9febaa5bad8150bdf632b97221a140e0e3cbd..8dab4e569571dd34096104f87e8ed27faa7d5522 100644 (file)
@@ -613,7 +613,7 @@ static int llc_wait_data(struct sock *sk, long timeo)
                if (signal_pending(current))
                        break;
                rc = 0;
-               if (sk_wait_data(sk, &timeo))
+               if (sk_wait_data(sk, &timeo, NULL))
                        break;
        }
        return rc;
@@ -802,7 +802,7 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                        release_sock(sk);
                        lock_sock(sk);
                } else
-                       sk_wait_data(sk, &timeo);
+                       sk_wait_data(sk, &timeo, NULL);
 
                if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) {
                        net_dbg_ratelimited("LLC(%s:%d): Application bug, race in MSG_PEEK\n",
index 29236e832e44470a4f13637847c2d1cbafb9bfb2..c09c0131bfa227e99346b180f501cc6fcf64644a 100644 (file)
@@ -723,6 +723,7 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
 
        debugfs_remove_recursive(sdata->vif.debugfs_dir);
        sdata->vif.debugfs_dir = NULL;
+       sdata->debugfs.subdir_stations = NULL;
 }
 
 void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
index ed1edac143729cc117c1cb63c5519285acff13a7..553ac6dd4867480048aed3ca0d430948f928d3c7 100644 (file)
@@ -1863,10 +1863,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
        ieee80211_teardown_sdata(sdata);
 }
 
-/*
- * Remove all interfaces, may only be called at hardware unregistration
- * time because it doesn't do RCU-safe list removals.
- */
 void ieee80211_remove_interfaces(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata, *tmp;
@@ -1875,14 +1871,21 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
 
        ASSERT_RTNL();
 
-       /*
-        * Close all AP_VLAN interfaces first, as otherwise they
-        * might be closed while the AP interface they belong to
-        * is closed, causing unregister_netdevice_many() to crash.
+       /* Before destroying the interfaces, make sure they're all stopped so
+        * that the hardware is stopped. Otherwise, the driver might still be
+        * iterating the interfaces during the shutdown, e.g. from a worker
+        * or from RX processing or similar, and if it does so (using atomic
+        * iteration) while we're manipulating the list, the iteration will
+        * crash.
+        *
+        * After this, the hardware should be stopped and the driver should
+        * have stopped all of its activities, so that we can do RCU-unaware
+        * manipulations of the interface list below.
         */
-       list_for_each_entry(sdata, &local->interfaces, list)
-               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       dev_close(sdata->dev);
+       cfg80211_shutdown_all_interfaces(local->hw.wiphy);
+
+       WARN(local->open_count, "%s: open count remains %d\n",
+            wiphy_name(local->hw.wiphy), local->open_count);
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
index 5438d13e2f007d1bca01ac97bb0f54867bef15ce..3b59099413fb1770e2ee2228065899bc5f9eb302 100644 (file)
@@ -306,7 +306,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
                        /* AID */
                        pos = skb_put(skb, 2);
-                       put_unaligned_le16(plid, pos + 2);
+                       put_unaligned_le16(plid, pos);
                }
                if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
                    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -1122,6 +1122,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
                                                WLAN_SP_MESH_PEERING_CONFIRM) {
                baseaddr += 4;
                baselen += 4;
+
+               if (baselen > len)
+                       return;
        }
        ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
        mesh_process_plink_frame(sdata, mgmt, &elems);
index 06b60980c62c62cf8c8f95e10052060be5d36ed8..b676b9fa707b3c8872a1065d8582b8ff1463e607 100644 (file)
@@ -76,6 +76,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                                continue;
                        ieee80211_mgd_quiesce(sdata);
+                       /* If suspended during TX in progress, and wowlan
+                        * is enabled (connection will be active) there
+                        * can be a race where the driver is put out
+                        * of power-save due to TX and during suspend
+                        * dynamic_ps_timer is cancelled and TX packet
+                        * is flushed, leaving the driver in ACTIVE even
+                        * after resuming until dynamic_ps_timer puts
+                        * driver back in DOZE.
+                        */
+                       if (sdata->u.mgd.associated &&
+                           sdata->u.mgd.powersave &&
+                            !(local->hw.conf.flags & IEEE80211_CONF_PS)) {
+                               local->hw.conf.flags |= IEEE80211_CONF_PS;
+                               ieee80211_hw_config(local,
+                                                   IEEE80211_CONF_CHANGE_PS);
+                       }
                }
 
                err = drv_suspend(local, wowlan);
index 247552a7f6c2f23a1e4bc89b647d8d37680bf2c3..3ece7d1034c81ae8749cada074fbebecbe06d57f 100644 (file)
@@ -92,14 +92,15 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
 static inline void
 minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
 {
-       int j = MAX_THR_RATES;
-       struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats;
+       int j;
+       struct minstrel_rate_stats *tmp_mrs;
        struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats;
 
-       while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) >
-              minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) {
-               j--;
+       for (j = MAX_THR_RATES; j > 0; --j) {
                tmp_mrs = &mi->r[tp_list[j - 1]].stats;
+               if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <=
+                   minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))
+                       break;
        }
 
        if (j < MAX_THR_RATES - 1)
index ad31b2dab4f5ab0731d53e54f00b30e65b085ec4..8db6e2994bbc59bb7cf38c36848a7d92b8e4a0e5 100644 (file)
@@ -60,6 +60,7 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_channel *ch;
        struct cfg80211_chan_def chandef;
        int i, subband_start;
+       struct wiphy *wiphy = sdata->local->hw.wiphy;
 
        for (i = start; i <= end; i += spacing) {
                if (!ch_cnt)
@@ -70,9 +71,8 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
                        /* we will be active on the channel */
                        cfg80211_chandef_create(&chandef, ch,
                                                NL80211_CHAN_NO_HT);
-                       if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
-                                                   &chandef,
-                                                   sdata->wdev.iftype)) {
+                       if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
+                                                         sdata->wdev.iftype)) {
                                ch_cnt++;
                                /*
                                 * check if the next channel is also part of
index 8410bb3bf5e8ddf5552fb0af84d05152425148dd..b8233505bf9fd3bb4945c126eebee069f2b94878 100644 (file)
@@ -1117,7 +1117,9 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                        queued = true;
                        info->control.vif = &tx->sdata->vif;
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-                       info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
+                       info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS |
+                                       IEEE80211_TX_CTL_NO_PS_BUFFER |
+                                       IEEE80211_TX_STATUS_EOSP;
                        __skb_queue_tail(&tid_tx->pending, skb);
                        if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
                                purge_skb = __skb_dequeue(&tid_tx->pending);
index 5d2b806a862e6834ff6c61aee5c0e0a899bbe4b8..38fbc194b9cb72835c497439713d23f16d99ca8c 100644 (file)
@@ -319,7 +319,13 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
                 * return *ignored=0 i.e. ICMP and NF_DROP
                 */
                sched = rcu_dereference(svc->scheduler);
-               dest = sched->schedule(svc, skb, iph);
+               if (sched) {
+                       /* read svc->sched_data after svc->scheduler */
+                       smp_rmb();
+                       dest = sched->schedule(svc, skb, iph);
+               } else {
+                       dest = NULL;
+               }
                if (!dest) {
                        IP_VS_DBG(1, "p-schedule: no dest found.\n");
                        kfree(param.pe_data);
@@ -467,7 +473,13 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
        }
 
        sched = rcu_dereference(svc->scheduler);
-       dest = sched->schedule(svc, skb, iph);
+       if (sched) {
+               /* read svc->sched_data after svc->scheduler */
+               smp_rmb();
+               dest = sched->schedule(svc, skb, iph);
+       } else {
+               dest = NULL;
+       }
        if (dest == NULL) {
                IP_VS_DBG(1, "Schedule: no dest found.\n");
                return NULL;
index 285eae3a145483c48c00493651a46a5d81656845..24c554201a766d175ed90359b6b78617acd37c64 100644 (file)
@@ -842,15 +842,16 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
        __ip_vs_dst_cache_reset(dest);
        spin_unlock_bh(&dest->dst_lock);
 
-       sched = rcu_dereference_protected(svc->scheduler, 1);
        if (add) {
                ip_vs_start_estimator(svc->net, &dest->stats);
                list_add_rcu(&dest->n_list, &svc->destinations);
                svc->num_dests++;
-               if (sched->add_dest)
+               sched = rcu_dereference_protected(svc->scheduler, 1);
+               if (sched && sched->add_dest)
                        sched->add_dest(svc, dest);
        } else {
-               if (sched->upd_dest)
+               sched = rcu_dereference_protected(svc->scheduler, 1);
+               if (sched && sched->upd_dest)
                        sched->upd_dest(svc, dest);
        }
 }
@@ -1084,7 +1085,7 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
                struct ip_vs_scheduler *sched;
 
                sched = rcu_dereference_protected(svc->scheduler, 1);
-               if (sched->del_dest)
+               if (sched && sched->del_dest)
                        sched->del_dest(svc, dest);
        }
 }
@@ -1175,11 +1176,14 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
        ip_vs_use_count_inc();
 
        /* Lookup the scheduler by 'u->sched_name' */
-       sched = ip_vs_scheduler_get(u->sched_name);
-       if (sched == NULL) {
-               pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
-               ret = -ENOENT;
-               goto out_err;
+       if (strcmp(u->sched_name, "none")) {
+               sched = ip_vs_scheduler_get(u->sched_name);
+               if (!sched) {
+                       pr_info("Scheduler module ip_vs_%s not found\n",
+                               u->sched_name);
+                       ret = -ENOENT;
+                       goto out_err;
+               }
        }
 
        if (u->pe_name && *u->pe_name) {
@@ -1240,10 +1244,12 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
        spin_lock_init(&svc->stats.lock);
 
        /* Bind the scheduler */
-       ret = ip_vs_bind_scheduler(svc, sched);
-       if (ret)
-               goto out_err;
-       sched = NULL;
+       if (sched) {
+               ret = ip_vs_bind_scheduler(svc, sched);
+               if (ret)
+                       goto out_err;
+               sched = NULL;
+       }
 
        /* Bind the ct retriever */
        RCU_INIT_POINTER(svc->pe, pe);
@@ -1291,17 +1297,20 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
 static int
 ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 {
-       struct ip_vs_scheduler *sched, *old_sched;
+       struct ip_vs_scheduler *sched = NULL, *old_sched;
        struct ip_vs_pe *pe = NULL, *old_pe = NULL;
        int ret = 0;
 
        /*
         * Lookup the scheduler, by 'u->sched_name'
         */
-       sched = ip_vs_scheduler_get(u->sched_name);
-       if (sched == NULL) {
-               pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
-               return -ENOENT;
+       if (strcmp(u->sched_name, "none")) {
+               sched = ip_vs_scheduler_get(u->sched_name);
+               if (!sched) {
+                       pr_info("Scheduler module ip_vs_%s not found\n",
+                               u->sched_name);
+                       return -ENOENT;
+               }
        }
        old_sched = sched;
 
@@ -1329,14 +1338,20 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 
        old_sched = rcu_dereference_protected(svc->scheduler, 1);
        if (sched != old_sched) {
+               if (old_sched) {
+                       ip_vs_unbind_scheduler(svc, old_sched);
+                       RCU_INIT_POINTER(svc->scheduler, NULL);
+                       /* Wait all svc->sched_data users */
+                       synchronize_rcu();
+               }
                /* Bind the new scheduler */
-               ret = ip_vs_bind_scheduler(svc, sched);
-               if (ret) {
-                       old_sched = sched;
-                       goto out;
+               if (sched) {
+                       ret = ip_vs_bind_scheduler(svc, sched);
+                       if (ret) {
+                               ip_vs_scheduler_put(sched);
+                               goto out;
+                       }
                }
-               /* Unbind the old scheduler on success */
-               ip_vs_unbind_scheduler(svc, old_sched);
        }
 
        /*
@@ -1982,6 +1997,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
                const struct ip_vs_iter *iter = seq->private;
                const struct ip_vs_dest *dest;
                struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
+               char *sched_name = sched ? sched->name : "none";
 
                if (iter->table == ip_vs_svc_table) {
 #ifdef CONFIG_IP_VS_IPV6
@@ -1990,18 +2006,18 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
                                           ip_vs_proto_name(svc->protocol),
                                           &svc->addr.in6,
                                           ntohs(svc->port),
-                                          sched->name);
+                                          sched_name);
                        else
 #endif
                                seq_printf(seq, "%s  %08X:%04X %s %s ",
                                           ip_vs_proto_name(svc->protocol),
                                           ntohl(svc->addr.ip),
                                           ntohs(svc->port),
-                                          sched->name,
+                                          sched_name,
                                           (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
                } else {
                        seq_printf(seq, "FWM  %08X %s %s",
-                                  svc->fwmark, sched->name,
+                                  svc->fwmark, sched_name,
                                   (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
                }
 
@@ -2427,13 +2443,15 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
 {
        struct ip_vs_scheduler *sched;
        struct ip_vs_kstats kstats;
+       char *sched_name;
 
        sched = rcu_dereference_protected(src->scheduler, 1);
+       sched_name = sched ? sched->name : "none";
        dst->protocol = src->protocol;
        dst->addr = src->addr.ip;
        dst->port = src->port;
        dst->fwmark = src->fwmark;
-       strlcpy(dst->sched_name, sched->name, sizeof(dst->sched_name));
+       strlcpy(dst->sched_name, sched_name, sizeof(dst->sched_name));
        dst->flags = src->flags;
        dst->timeout = src->timeout / HZ;
        dst->netmask = src->netmask;
@@ -2892,6 +2910,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
        struct ip_vs_flags flags = { .flags = svc->flags,
                                     .mask = ~0 };
        struct ip_vs_kstats kstats;
+       char *sched_name;
 
        nl_service = nla_nest_start(skb, IPVS_CMD_ATTR_SERVICE);
        if (!nl_service)
@@ -2910,8 +2929,9 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
        }
 
        sched = rcu_dereference_protected(svc->scheduler, 1);
+       sched_name = sched ? sched->name : "none";
        pe = rcu_dereference_protected(svc->pe, 1);
-       if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched->name) ||
+       if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched_name) ||
            (pe && nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, pe->name)) ||
            nla_put(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags) ||
            nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) ||
index 199760c71f3995f88dbe73b159906cf7840cdded..7e814164794346daf6038e4b45cb5e1f8c762813 100644 (file)
@@ -74,7 +74,7 @@ void ip_vs_unbind_scheduler(struct ip_vs_service *svc,
 
        if (sched->done_service)
                sched->done_service(svc);
-       /* svc->scheduler can not be set to NULL */
+       /* svc->scheduler can be set to NULL only by caller */
 }
 
 
@@ -147,21 +147,21 @@ void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
 
 void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg)
 {
-       struct ip_vs_scheduler *sched;
+       struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
+       char *sched_name = sched ? sched->name : "none";
 
-       sched = rcu_dereference(svc->scheduler);
        if (svc->fwmark) {
                IP_VS_ERR_RL("%s: FWM %u 0x%08X - %s\n",
-                            sched->name, svc->fwmark, svc->fwmark, msg);
+                            sched_name, svc->fwmark, svc->fwmark, msg);
 #ifdef CONFIG_IP_VS_IPV6
        } else if (svc->af == AF_INET6) {
                IP_VS_ERR_RL("%s: %s [%pI6c]:%d - %s\n",
-                            sched->name, ip_vs_proto_name(svc->protocol),
+                            sched_name, ip_vs_proto_name(svc->protocol),
                             &svc->addr.in6, ntohs(svc->port), msg);
 #endif
        } else {
                IP_VS_ERR_RL("%s: %s %pI4:%d - %s\n",
-                            sched->name, ip_vs_proto_name(svc->protocol),
+                            sched_name, ip_vs_proto_name(svc->protocol),
                             &svc->addr.ip, ntohs(svc->port), msg);
        }
 }
index b08ba9538d121bad95ab9aa579b2b37523f57dc2..d99ad93eb85508594cc5f6919a0b9eb005f19b33 100644 (file)
@@ -612,7 +612,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp,
                        pkts = atomic_add_return(1, &cp->in_pkts);
                else
                        pkts = sysctl_sync_threshold(ipvs);
-               ip_vs_sync_conn(net, cp->control, pkts);
+               ip_vs_sync_conn(net, cp, pkts);
        }
 }
 
index bf66a8657a5f7c7e1a2d3adbde3a05245c598249..258a0b0e82a293db38533a114c5c3a0bb2c03b9f 100644 (file)
@@ -130,7 +130,6 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr,
 
        memset(&fl4, 0, sizeof(fl4));
        fl4.daddr = daddr;
-       fl4.saddr = (rt_mode & IP_VS_RT_MODE_CONNECT) ? *saddr : 0;
        fl4.flowi4_flags = (rt_mode & IP_VS_RT_MODE_KNOWN_NH) ?
                           FLOWI_FLAG_KNOWN_NH : 0;
 
@@ -505,6 +504,13 @@ err_put:
        return -1;
 
 err_unreach:
+       /* The ip6_link_failure function requires the dev field to be set
+        * in order to get the net (further for the sake of fwmark
+        * reflection).
+        */
+       if (!skb->dev)
+               skb->dev = skb_dst(skb)->dev;
+
        dst_link_failure(skb);
        return -1;
 }
@@ -523,10 +529,27 @@ static inline int ip_vs_tunnel_xmit_prepare(struct sk_buff *skb,
        if (ret == NF_ACCEPT) {
                nf_reset(skb);
                skb_forward_csum(skb);
+               if (!skb->sk)
+                       skb_sender_cpu_clear(skb);
        }
        return ret;
 }
 
+/* In the event of a remote destination, it's possible that we would have
+ * matches against an old socket (particularly a TIME-WAIT socket). This
+ * causes havoc down the line (ip_local_out et. al. expect regular sockets
+ * and invalid memory accesses will happen) so simply drop the association
+ * in this case.
+*/
+static inline void ip_vs_drop_early_demux_sk(struct sk_buff *skb)
+{
+       /* If dev is set, the packet came from the LOCAL_IN callback and
+        * not from a local TCP socket.
+        */
+       if (skb->dev)
+               skb_orphan(skb);
+}
+
 /* return NF_STOLEN (sent) or NF_ACCEPT if local=1 (not sent) */
 static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb,
                                         struct ip_vs_conn *cp, int local)
@@ -538,12 +561,23 @@ static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb,
                ip_vs_notrack(skb);
        else
                ip_vs_update_conntrack(skb, cp, 1);
+
+       /* Remove the early_demux association unless it's bound for the
+        * exact same port and address on this host after translation.
+        */
+       if (!local || cp->vport != cp->dport ||
+           !ip_vs_addr_equal(cp->af, &cp->vaddr, &cp->daddr))
+               ip_vs_drop_early_demux_sk(skb);
+
        if (!local) {
                skb_forward_csum(skb);
+               if (!skb->sk)
+                       skb_sender_cpu_clear(skb);
                NF_HOOK(pf, NF_INET_LOCAL_OUT, NULL, skb,
                        NULL, skb_dst(skb)->dev, dst_output_sk);
        } else
                ret = NF_ACCEPT;
+
        return ret;
 }
 
@@ -557,7 +591,10 @@ static inline int ip_vs_send_or_cont(int pf, struct sk_buff *skb,
        if (likely(!(cp->flags & IP_VS_CONN_F_NFCT)))
                ip_vs_notrack(skb);
        if (!local) {
+               ip_vs_drop_early_demux_sk(skb);
                skb_forward_csum(skb);
+               if (!skb->sk)
+                       skb_sender_cpu_clear(skb);
                NF_HOOK(pf, NF_INET_LOCAL_OUT, NULL, skb,
                        NULL, skb_dst(skb)->dev, dst_output_sk);
        } else
@@ -845,6 +882,8 @@ ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af,
        struct ipv6hdr *old_ipv6h = NULL;
 #endif
 
+       ip_vs_drop_early_demux_sk(skb);
+
        if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
                new_skb = skb_realloc_headroom(skb, max_headroom);
                if (!new_skb)
index 13fad8668f83d7ea4c7862b4c24d1234475ac37d..3c20d02aee738c5293a5b449f28ebff596c7232d 100644 (file)
@@ -287,6 +287,46 @@ static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct)
        spin_unlock(&pcpu->lock);
 }
 
+/* Released via destroy_conntrack() */
+struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags)
+{
+       struct nf_conn *tmpl;
+
+       tmpl = kzalloc(sizeof(*tmpl), flags);
+       if (tmpl == NULL)
+               return NULL;
+
+       tmpl->status = IPS_TEMPLATE;
+       write_pnet(&tmpl->ct_net, net);
+
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       if (zone) {
+               struct nf_conntrack_zone *nf_ct_zone;
+
+               nf_ct_zone = nf_ct_ext_add(tmpl, NF_CT_EXT_ZONE, flags);
+               if (!nf_ct_zone)
+                       goto out_free;
+               nf_ct_zone->id = zone;
+       }
+#endif
+       atomic_set(&tmpl->ct_general.use, 0);
+
+       return tmpl;
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+out_free:
+       kfree(tmpl);
+       return NULL;
+#endif
+}
+EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc);
+
+static void nf_ct_tmpl_free(struct nf_conn *tmpl)
+{
+       nf_ct_ext_destroy(tmpl);
+       nf_ct_ext_free(tmpl);
+       kfree(tmpl);
+}
+
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
@@ -298,6 +338,10 @@ destroy_conntrack(struct nf_conntrack *nfct)
        NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
        NF_CT_ASSERT(!timer_pending(&ct->timeout));
 
+       if (unlikely(nf_ct_is_template(ct))) {
+               nf_ct_tmpl_free(ct);
+               return;
+       }
        rcu_read_lock();
        l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
        if (l4proto && l4proto->destroy)
@@ -540,28 +584,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
 
-/* deletion from this larval template list happens via nf_ct_put() */
-void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
-{
-       struct ct_pcpu *pcpu;
-
-       __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
-       __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
-       nf_conntrack_get(&tmpl->ct_general);
-
-       /* add this conntrack to the (per cpu) tmpl list */
-       local_bh_disable();
-       tmpl->cpu = smp_processor_id();
-       pcpu = per_cpu_ptr(nf_ct_net(tmpl)->ct.pcpu_lists, tmpl->cpu);
-
-       spin_lock(&pcpu->lock);
-       /* Overload tuple linked list to put us in template list. */
-       hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                                &pcpu->tmpl);
-       spin_unlock_bh(&pcpu->lock);
-}
-EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
-
 /* Confirm a connection given skb; places it in hash table */
 int
 __nf_conntrack_confirm(struct sk_buff *skb)
@@ -1522,10 +1544,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
        sz = nr_slots * sizeof(struct hlist_nulls_head);
        hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
                                        get_order(sz));
-       if (!hash) {
-               printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
+       if (!hash)
                hash = vzalloc(sz);
-       }
 
        if (hash && nulls)
                for (i = 0; i < nr_slots; i++)
@@ -1751,7 +1771,6 @@ int nf_conntrack_init_net(struct net *net)
                spin_lock_init(&pcpu->lock);
                INIT_HLIST_NULLS_HEAD(&pcpu->unconfirmed, UNCONFIRMED_NULLS_VAL);
                INIT_HLIST_NULLS_HEAD(&pcpu->dying, DYING_NULLS_VAL);
-               INIT_HLIST_NULLS_HEAD(&pcpu->tmpl, TEMPLATE_NULLS_VAL);
        }
 
        net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
index 7a17070c5dabb979c2cb90b7b62f35a79cdc92c0..b45a4223cb058a47ae2863a4166cd5085e587ca6 100644 (file)
@@ -219,7 +219,8 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
                        a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
        }
 
-       return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
+       return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask) &&
+              nf_ct_zone(a->master) == nf_ct_zone(b->master);
 }
 
 static inline int expect_matches(const struct nf_conntrack_expect *a,
index d1c23940a86ad96cddbf1aefe0747c43fddca920..6b8b0abbfab482280ae6a318f8bc58260e0b21c8 100644 (file)
@@ -2995,11 +2995,6 @@ ctnetlink_create_expect(struct net *net, u16 zone,
        }
 
        err = nf_ct_expect_related_report(exp, portid, report);
-       if (err < 0)
-               goto err_exp;
-
-       return 0;
-err_exp:
        nf_ct_expect_put(exp);
 err_ct:
        nf_ct_put(ct);
index cd60d397fe056f14ee4c310d75c4fba3f504cf71..8a8b2abc35ffdeacb5a61e1a801c92f91998bc3d 100644 (file)
@@ -213,7 +213,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
 
        if (verdict == NF_ACCEPT) {
        next_hook:
-               verdict = nf_iterate(&nf_hooks[entry->state.pf][entry->state.hook],
+               verdict = nf_iterate(entry->state.hook_list,
                                     skb, &entry->state, &elem);
        }
 
index 789feeae6c44a82b44e040ae2a6bec6f26cbe450..d7f1685279034b5e3b62748284d24c52cc1f8907 100644 (file)
@@ -349,23 +349,20 @@ static void __net_exit synproxy_proc_exit(struct net *net)
 static int __net_init synproxy_net_init(struct net *net)
 {
        struct synproxy_net *snet = synproxy_pernet(net);
-       struct nf_conntrack_tuple t;
        struct nf_conn *ct;
        int err = -ENOMEM;
 
-       memset(&t, 0, sizeof(t));
-       ct = nf_conntrack_alloc(net, 0, &t, &t, GFP_KERNEL);
-       if (IS_ERR(ct)) {
-               err = PTR_ERR(ct);
+       ct = nf_ct_tmpl_alloc(net, 0, GFP_KERNEL);
+       if (!ct)
                goto err1;
-       }
 
        if (!nfct_seqadj_ext_add(ct))
                goto err2;
        if (!nfct_synproxy_ext_add(ct))
                goto err2;
 
-       nf_conntrack_tmpl_insert(net, ct);
+       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+       nf_conntrack_get(&ct->ct_general);
        snet->tmpl = ct;
 
        snet->stats = alloc_percpu(struct synproxy_stats);
index 8b117c90ecd765ac1b7242c58f36ef7531a49b6e..0c0e8ecf02abbb4214b18f00ef798d728234866b 100644 (file)
@@ -269,6 +269,12 @@ static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb)
        }
 }
 
+enum {
+       NFNL_BATCH_FAILURE      = (1 << 0),
+       NFNL_BATCH_DONE         = (1 << 1),
+       NFNL_BATCH_REPLAY       = (1 << 2),
+};
+
 static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
                                u_int16_t subsys_id)
 {
@@ -276,13 +282,15 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct net *net = sock_net(skb->sk);
        const struct nfnetlink_subsystem *ss;
        const struct nfnl_callback *nc;
-       bool success = true, done = false;
        static LIST_HEAD(err_list);
+       u32 status;
        int err;
 
        if (subsys_id >= NFNL_SUBSYS_COUNT)
                return netlink_ack(skb, nlh, -EINVAL);
 replay:
+       status = 0;
+
        skb = netlink_skb_clone(oskb, GFP_KERNEL);
        if (!skb)
                return netlink_ack(oskb, nlh, -ENOMEM);
@@ -336,10 +344,10 @@ replay:
                if (type == NFNL_MSG_BATCH_BEGIN) {
                        /* Malformed: Batch begin twice */
                        nfnl_err_reset(&err_list);
-                       success = false;
+                       status |= NFNL_BATCH_FAILURE;
                        goto done;
                } else if (type == NFNL_MSG_BATCH_END) {
-                       done = true;
+                       status |= NFNL_BATCH_DONE;
                        goto done;
                } else if (type < NLMSG_MIN_TYPE) {
                        err = -EINVAL;
@@ -382,11 +390,8 @@ replay:
                         * original skb.
                         */
                        if (err == -EAGAIN) {
-                               nfnl_err_reset(&err_list);
-                               ss->abort(oskb);
-                               nfnl_unlock(subsys_id);
-                               kfree_skb(skb);
-                               goto replay;
+                               status |= NFNL_BATCH_REPLAY;
+                               goto next;
                        }
                }
 ack:
@@ -402,7 +407,7 @@ ack:
                                 */
                                nfnl_err_reset(&err_list);
                                netlink_ack(skb, nlmsg_hdr(oskb), -ENOMEM);
-                               success = false;
+                               status |= NFNL_BATCH_FAILURE;
                                goto done;
                        }
                        /* We don't stop processing the batch on errors, thus,
@@ -410,19 +415,26 @@ ack:
                         * triggers.
                         */
                        if (err)
-                               success = false;
+                               status |= NFNL_BATCH_FAILURE;
                }
-
+next:
                msglen = NLMSG_ALIGN(nlh->nlmsg_len);
                if (msglen > skb->len)
                        msglen = skb->len;
                skb_pull(skb, msglen);
        }
 done:
-       if (success && done)
+       if (status & NFNL_BATCH_REPLAY) {
+               ss->abort(oskb);
+               nfnl_err_reset(&err_list);
+               nfnl_unlock(subsys_id);
+               kfree_skb(skb);
+               goto replay;
+       } else if (status == NFNL_BATCH_DONE) {
                ss->commit(oskb);
-       else
+       } else {
                ss->abort(oskb);
+       }
 
        nfnl_err_deliver(&err_list, oskb);
        nfnl_unlock(subsys_id);
index 75747aecdebe6344ccbfcf178c299be013d8f763..43ddeee404e91f97908fb9228c1e873931b75bcc 100644 (file)
@@ -184,7 +184,6 @@ out:
 static int xt_ct_tg_check(const struct xt_tgchk_param *par,
                          struct xt_ct_target_info_v1 *info)
 {
-       struct nf_conntrack_tuple t;
        struct nf_conn *ct;
        int ret = -EOPNOTSUPP;
 
@@ -202,11 +201,11 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
        if (ret < 0)
                goto err1;
 
-       memset(&t, 0, sizeof(t));
-       ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
-       ret = PTR_ERR(ct);
-       if (IS_ERR(ct))
+       ct = nf_ct_tmpl_alloc(par->net, info->zone, GFP_KERNEL);
+       if (!ct) {
+               ret = -ENOMEM;
                goto err2;
+       }
 
        ret = 0;
        if ((info->ct_events || info->exp_events) &&
@@ -227,8 +226,8 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
                if (ret < 0)
                        goto err3;
        }
-
-       nf_conntrack_tmpl_insert(par->net, ct);
+       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+       nf_conntrack_get(&ct->ct_general);
 out:
        info->ct = ct;
        return 0;
index f407ebc13481ae5caa0f634db643d034c7af7e6a..29d2c31f406ca585d5f0eb1f08bcaf26d8364053 100644 (file)
@@ -126,6 +126,7 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
                goto out;
        }
 
+       sysfs_attr_init(&info->timer->attr.attr);
        info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL);
        if (!info->timer->attr.attr.name) {
                ret = -ENOMEM;
index dea925388a5b7a86ba649f888fb10bb805f54edb..67d2104778636c62e7d3fa94c73ce5fb2cd4cb7d 100644 (file)
@@ -158,7 +158,7 @@ static int __netlink_remove_tap(struct netlink_tap *nt)
 out:
        spin_unlock(&netlink_tap_lock);
 
-       if (found && nt->module)
+       if (found)
                module_put(nt->module);
 
        return found ? 0 : -ENODEV;
@@ -357,25 +357,52 @@ err1:
        return NULL;
 }
 
+
+static void
+__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, void **pg_vec,
+                  unsigned int order)
+{
+       struct netlink_sock *nlk = nlk_sk(sk);
+       struct sk_buff_head *queue;
+       struct netlink_ring *ring;
+
+       queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
+       ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
+
+       spin_lock_bh(&queue->lock);
+
+       ring->frame_max         = req->nm_frame_nr - 1;
+       ring->head              = 0;
+       ring->frame_size        = req->nm_frame_size;
+       ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
+
+       swap(ring->pg_vec_len, req->nm_block_nr);
+       swap(ring->pg_vec_order, order);
+       swap(ring->pg_vec, pg_vec);
+
+       __skb_queue_purge(queue);
+       spin_unlock_bh(&queue->lock);
+
+       WARN_ON(atomic_read(&nlk->mapped));
+
+       if (pg_vec)
+               free_pg_vec(pg_vec, order, req->nm_block_nr);
+}
+
 static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
-                           bool closing, bool tx_ring)
+                           bool tx_ring)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
        struct netlink_ring *ring;
-       struct sk_buff_head *queue;
        void **pg_vec = NULL;
        unsigned int order = 0;
-       int err;
 
        ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
-       queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
 
-       if (!closing) {
-               if (atomic_read(&nlk->mapped))
-                       return -EBUSY;
-               if (atomic_read(&ring->pending))
-                       return -EBUSY;
-       }
+       if (atomic_read(&nlk->mapped))
+               return -EBUSY;
+       if (atomic_read(&ring->pending))
+               return -EBUSY;
 
        if (req->nm_block_nr) {
                if (ring->pg_vec != NULL)
@@ -407,31 +434,19 @@ static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
                        return -EINVAL;
        }
 
-       err = -EBUSY;
        mutex_lock(&nlk->pg_vec_lock);
-       if (closing || atomic_read(&nlk->mapped) == 0) {
-               err = 0;
-               spin_lock_bh(&queue->lock);
-
-               ring->frame_max         = req->nm_frame_nr - 1;
-               ring->head              = 0;
-               ring->frame_size        = req->nm_frame_size;
-               ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
-
-               swap(ring->pg_vec_len, req->nm_block_nr);
-               swap(ring->pg_vec_order, order);
-               swap(ring->pg_vec, pg_vec);
-
-               __skb_queue_purge(queue);
-               spin_unlock_bh(&queue->lock);
-
-               WARN_ON(atomic_read(&nlk->mapped));
+       if (atomic_read(&nlk->mapped) == 0) {
+               __netlink_set_ring(sk, req, tx_ring, pg_vec, order);
+               mutex_unlock(&nlk->pg_vec_lock);
+               return 0;
        }
+
        mutex_unlock(&nlk->pg_vec_lock);
 
        if (pg_vec)
                free_pg_vec(pg_vec, order, req->nm_block_nr);
-       return err;
+
+       return -EBUSY;
 }
 
 static void netlink_mm_open(struct vm_area_struct *vma)
@@ -900,10 +915,10 @@ static void netlink_sock_destruct(struct sock *sk)
 
                memset(&req, 0, sizeof(req));
                if (nlk->rx_ring.pg_vec)
-                       netlink_set_ring(sk, &req, true, false);
+                       __netlink_set_ring(sk, &req, false, NULL, 0);
                memset(&req, 0, sizeof(req));
                if (nlk->tx_ring.pg_vec)
-                       netlink_set_ring(sk, &req, true, true);
+                       __netlink_set_ring(sk, &req, true, NULL, 0);
        }
 #endif /* CONFIG_NETLINK_MMAP */
 
@@ -1081,6 +1096,11 @@ static int netlink_insert(struct sock *sk, u32 portid)
 
        err = __netlink_insert(table, sk);
        if (err) {
+               /* In case the hashtable backend returns with -EBUSY
+                * from here, it must not escape to the caller.
+                */
+               if (unlikely(err == -EBUSY))
+                       err = -EOVERFLOW;
                if (err == -EEXIST)
                        err = -EADDRINUSE;
                nlk_sk(sk)->portid = 0;
@@ -2223,7 +2243,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                        return -EINVAL;
                if (copy_from_user(&req, optval, sizeof(req)))
                        return -EFAULT;
-               err = netlink_set_ring(sk, &req, false,
+               err = netlink_set_ring(sk, &req,
                                       optname == NETLINK_TX_RING);
                break;
        }
index 8a8c0b8b4f63a4bd8e5ff776250189558e6fcb1e..ee34f474ad1465087da8fd506410559abe47d81e 100644 (file)
@@ -273,28 +273,36 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
        return 0;
 }
 
-static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
-                       __be32 *addr, __be32 new_addr)
+static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
+                                 __be32 addr, __be32 new_addr)
 {
        int transport_len = skb->len - skb_transport_offset(skb);
 
+       if (nh->frag_off & htons(IP_OFFSET))
+               return;
+
        if (nh->protocol == IPPROTO_TCP) {
                if (likely(transport_len >= sizeof(struct tcphdr)))
                        inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
-                                                *addr, new_addr, 1);
+                                                addr, new_addr, 1);
        } else if (nh->protocol == IPPROTO_UDP) {
                if (likely(transport_len >= sizeof(struct udphdr))) {
                        struct udphdr *uh = udp_hdr(skb);
 
                        if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
                                inet_proto_csum_replace4(&uh->check, skb,
-                                                        *addr, new_addr, 1);
+                                                        addr, new_addr, 1);
                                if (!uh->check)
                                        uh->check = CSUM_MANGLED_0;
                        }
                }
        }
+}
 
+static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
+                       __be32 *addr, __be32 new_addr)
+{
+       update_ip_l4_checksum(skb, nh, *addr, new_addr);
        csum_replace4(&nh->check, *addr, new_addr);
        skb_clear_hash(skb);
        *addr = new_addr;
index 4613df8c82900e32a4e0188688c9e0354022484d..65523948fb95e7cf7843efd447c7fc62b0c51b71 100644 (file)
@@ -752,7 +752,7 @@ int ovs_flow_init(void)
        BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
 
        flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow)
-                                      + (num_possible_nodes()
+                                      + (nr_node_ids
                                          * sizeof(struct flow_stats *)),
                                       0, 0, NULL);
        if (flow_cache == NULL)
index c9e8741226c6d8785e89532aa09e029c3fd9e487..ed458b315ef4153233f65fa2af0bb0db55225bf8 100644 (file)
@@ -2403,7 +2403,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                }
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
                                          addr, hlen);
-               if (tp_len > dev->mtu + dev->hard_header_len) {
+               if (likely(tp_len >= 0) &&
+                   tp_len > dev->mtu + dev->hard_header_len) {
                        struct ethhdr *ehdr;
                        /* Earlier code assumed this would be a VLAN pkt,
                         * double-check this now that we have the actual
@@ -2784,7 +2785,7 @@ static int packet_release(struct socket *sock)
 static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
 {
        struct packet_sock *po = pkt_sk(sk);
-       const struct net_device *dev_curr;
+       struct net_device *dev_curr;
        __be16 proto_curr;
        bool need_rehook;
 
@@ -2808,15 +2809,13 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
 
                po->num = proto;
                po->prot_hook.type = proto;
-
-               if (po->prot_hook.dev)
-                       dev_put(po->prot_hook.dev);
-
                po->prot_hook.dev = dev;
 
                po->ifindex = dev ? dev->ifindex : 0;
                packet_cached_dev_assign(po, dev);
        }
+       if (dev_curr)
+               dev_put(dev_curr);
 
        if (proto == 0 || !need_rehook)
                goto out_unlock;
index 273b8bff6ba448aa013932f5ac7c9f929f49aa70..657ba9f5d30862a1f8add1302e8364bcd4ad44dc 100644 (file)
@@ -759,8 +759,10 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
        }
 
        ibmr = rds_ib_alloc_fmr(rds_ibdev);
-       if (IS_ERR(ibmr))
+       if (IS_ERR(ibmr)) {
+               rds_ib_dev_put(rds_ibdev);
                return ibmr;
+       }
 
        ret = rds_ib_map_fmr(rds_ibdev, ibmr, sg, nents);
        if (ret == 0)
index 9a6b4f66187cf3e5ab533cd01344c9856834ebb7..140a44a5f7b7f1c08b3f329707b72fc75a9a81fe 100644 (file)
@@ -176,7 +176,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
 
        /* check for all kinds of wrapping and the like */
        start = (unsigned long)optval;
-       if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) {
+       if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
                ret = -EINVAL;
                goto out;
        }
index 8b4a6cd2c3a78f0a4c7dbbf89fbe1bd6156aeb55..83498e1c75b83f3230dace76da031a6f46753ee9 100644 (file)
@@ -73,7 +73,7 @@ EXPORT_SYMBOL_GPL(rds_trans_unregister);
 
 void rds_trans_put(struct rds_transport *trans)
 {
-       if (trans && trans->t_owner)
+       if (trans)
                module_put(trans->t_owner);
 }
 
index af427a3dbcba238103169ab2a58005feda5fa2f1..43ec92680ae8fe30d14496f5cf81a1baf53b49e3 100644 (file)
@@ -45,7 +45,7 @@ void tcf_hash_destroy(struct tc_action *a)
 }
 EXPORT_SYMBOL(tcf_hash_destroy);
 
-int tcf_hash_release(struct tc_action *a, int bind)
+int __tcf_hash_release(struct tc_action *a, bool bind, bool strict)
 {
        struct tcf_common *p = a->priv;
        int ret = 0;
@@ -53,7 +53,7 @@ int tcf_hash_release(struct tc_action *a, int bind)
        if (p) {
                if (bind)
                        p->tcfc_bindcnt--;
-               else if (p->tcfc_bindcnt > 0)
+               else if (strict && p->tcfc_bindcnt > 0)
                        return -EPERM;
 
                p->tcfc_refcnt--;
@@ -64,9 +64,10 @@ int tcf_hash_release(struct tc_action *a, int bind)
                        ret = 1;
                }
        }
+
        return ret;
 }
-EXPORT_SYMBOL(tcf_hash_release);
+EXPORT_SYMBOL(__tcf_hash_release);
 
 static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
                           struct tc_action *a)
@@ -136,7 +137,7 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
                head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
                hlist_for_each_entry_safe(p, n, head, tcfc_head) {
                        a->priv = p;
-                       ret = tcf_hash_release(a, 0);
+                       ret = __tcf_hash_release(a, false, true);
                        if (ret == ACT_P_DELETED) {
                                module_put(a->ops->owner);
                                n_i++;
@@ -408,7 +409,7 @@ int tcf_action_destroy(struct list_head *actions, int bind)
        int ret = 0;
 
        list_for_each_entry_safe(a, tmp, actions, list) {
-               ret = tcf_hash_release(a, bind);
+               ret = __tcf_hash_release(a, bind, true);
                if (ret == ACT_P_DELETED)
                        module_put(a->ops->owner);
                else if (ret < 0)
index 1d56903fd4c79aa008c4c540aabd8b4c099e81a1..d0edeb7a1950b9a4c087f67344af0402aaa550e1 100644 (file)
 struct tcf_bpf_cfg {
        struct bpf_prog *filter;
        struct sock_filter *bpf_ops;
-       char *bpf_name;
+       const char *bpf_name;
        u32 bpf_fd;
        u16 bpf_num_ops;
+       bool is_ebpf;
 };
 
 static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act,
@@ -207,6 +208,7 @@ static int tcf_bpf_init_from_ops(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
        cfg->bpf_ops = bpf_ops;
        cfg->bpf_num_ops = bpf_num_ops;
        cfg->filter = fp;
+       cfg->is_ebpf = false;
 
        return 0;
 }
@@ -241,18 +243,40 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
        cfg->bpf_fd = bpf_fd;
        cfg->bpf_name = name;
        cfg->filter = fp;
+       cfg->is_ebpf = true;
 
        return 0;
 }
 
+static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg)
+{
+       if (cfg->is_ebpf)
+               bpf_prog_put(cfg->filter);
+       else
+               bpf_prog_destroy(cfg->filter);
+
+       kfree(cfg->bpf_ops);
+       kfree(cfg->bpf_name);
+}
+
+static void tcf_bpf_prog_fill_cfg(const struct tcf_bpf *prog,
+                                 struct tcf_bpf_cfg *cfg)
+{
+       cfg->is_ebpf = tcf_bpf_is_ebpf(prog);
+       cfg->filter = prog->filter;
+
+       cfg->bpf_ops = prog->bpf_ops;
+       cfg->bpf_name = prog->bpf_name;
+}
+
 static int tcf_bpf_init(struct net *net, struct nlattr *nla,
                        struct nlattr *est, struct tc_action *act,
                        int replace, int bind)
 {
        struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
+       struct tcf_bpf_cfg cfg, old;
        struct tc_act_bpf *parm;
        struct tcf_bpf *prog;
-       struct tcf_bpf_cfg cfg;
        bool is_bpf, is_ebpf;
        int ret;
 
@@ -301,6 +325,9 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
        prog = to_bpf(act);
        spin_lock_bh(&prog->tcf_lock);
 
+       if (ret != ACT_P_CREATED)
+               tcf_bpf_prog_fill_cfg(prog, &old);
+
        prog->bpf_ops = cfg.bpf_ops;
        prog->bpf_name = cfg.bpf_name;
 
@@ -316,29 +343,22 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
 
        if (ret == ACT_P_CREATED)
                tcf_hash_insert(act);
+       else
+               tcf_bpf_cfg_cleanup(&old);
 
        return ret;
 
 destroy_fp:
-       if (is_ebpf)
-               bpf_prog_put(cfg.filter);
-       else
-               bpf_prog_destroy(cfg.filter);
-
-       kfree(cfg.bpf_ops);
-       kfree(cfg.bpf_name);
-
+       tcf_bpf_cfg_cleanup(&cfg);
        return ret;
 }
 
 static void tcf_bpf_cleanup(struct tc_action *act, int bind)
 {
-       const struct tcf_bpf *prog = act->priv;
+       struct tcf_bpf_cfg tmp;
 
-       if (tcf_bpf_is_ebpf(prog))
-               bpf_prog_put(prog->filter);
-       else
-               bpf_prog_destroy(prog->filter);
+       tcf_bpf_prog_fill_cfg(act->priv, &tmp);
+       tcf_bpf_cfg_cleanup(&tmp);
 }
 
 static struct tc_action_ops act_bpf_ops __read_mostly = {
index a42a3b257226178eb5af04054a17813c04368613..268545050ddbd67245ead8394a82f44503657ea5 100644 (file)
@@ -98,6 +98,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                        return ret;
                ret = ACT_P_CREATED;
        } else {
+               if (bind)
+                       return 0;
                if (!ovr) {
                        tcf_hash_release(a, bind);
                        return -EEXIST;
index 17e6d6669c7fdf138915ac9549d3f06d9535d745..ff8b466a73f6c04510523843b800de6c0db4b093 100644 (file)
@@ -68,13 +68,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
                }
                ret = ACT_P_CREATED;
        } else {
-               p = to_pedit(a);
-               tcf_hash_release(a, bind);
                if (bind)
                        return 0;
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
-
+               p = to_pedit(a);
                if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
                        keys = kmalloc(ksize, GFP_KERNEL);
                        if (keys == NULL)
index c79ecfd36e0f028388ea5f96a64dbb23451b01b1..e5168f8b9640964ce2dd95a896a24f6c986a959a 100644 (file)
@@ -378,7 +378,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
                goto errout;
 
        if (oldprog) {
-               list_replace_rcu(&prog->link, &oldprog->link);
+               list_replace_rcu(&oldprog->link, &prog->link);
                tcf_unbind_filter(tp, &oldprog->res);
                call_rcu(&oldprog->rcu, __cls_bpf_delete_prog);
        } else {
index 76bc3a20ffdb31bb4c9b51942de74c64928c2a3a..bb2a0f529c1f519f79f22ffa046013d7ac863eb5 100644 (file)
@@ -425,6 +425,8 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
        if (!fnew)
                goto err2;
 
+       tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
+
        fold = (struct flow_filter *)*arg;
        if (fold) {
                err = -EINVAL;
@@ -486,7 +488,6 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
                fnew->mask  = ~0U;
                fnew->tp = tp;
                get_random_bytes(&fnew->hashrnd, 4);
-               tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
        }
 
        fnew->perturb_timer.function = flow_perturbation;
@@ -526,7 +527,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
        if (*arg == 0)
                list_add_tail_rcu(&fnew->list, &head->filters);
        else
-               list_replace_rcu(&fnew->list, &fold->list);
+               list_replace_rcu(&fold->list, &fnew->list);
 
        *arg = (unsigned long)fnew;
 
index 9d37ccd95062a6840d1bb1e140b173dd1fe0b9d0..2f3d03f99487ed35c4af1e5c7ede590e4b0e3721 100644 (file)
@@ -499,7 +499,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        *arg = (unsigned long) fnew;
 
        if (fold) {
-               list_replace_rcu(&fnew->list, &fold->list);
+               list_replace_rcu(&fold->list, &fnew->list);
                tcf_unbind_filter(tp, &fold->res);
                call_rcu(&fold->rcu, fl_destroy_filter);
        } else {
index 93d5742dc7e0f9730abd1726adf47857de1e64d4..6a783afe4960052912bf1241a22ab16d38d9e81a 100644 (file)
@@ -385,6 +385,19 @@ static void choke_reset(struct Qdisc *sch)
 {
        struct choke_sched_data *q = qdisc_priv(sch);
 
+       while (q->head != q->tail) {
+               struct sk_buff *skb = q->tab[q->head];
+
+               q->head = (q->head + 1) & q->tab_mask;
+               if (!skb)
+                       continue;
+               qdisc_qstats_backlog_dec(sch, skb);
+               --sch->q.qlen;
+               qdisc_drop(skb, sch);
+       }
+
+       memset(q->tab, 0, (q->tab_mask + 1) * sizeof(struct sk_buff *));
+       q->head = q->tail = 0;
        red_restart(&q->vars);
 }
 
index d75993f89facc0ce8d5df0d26aedcd016714a43e..a9ba030435a2a5c2ca4bea21d62c6d631c6168f4 100644 (file)
@@ -155,14 +155,23 @@ static unsigned int fq_codel_drop(struct Qdisc *sch)
        skb = dequeue_head(flow);
        len = qdisc_pkt_len(skb);
        q->backlogs[idx] -= len;
-       kfree_skb(skb);
        sch->q.qlen--;
        qdisc_qstats_drop(sch);
        qdisc_qstats_backlog_dec(sch, skb);
+       kfree_skb(skb);
        flow->dropped++;
        return idx;
 }
 
+static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch)
+{
+       unsigned int prev_backlog;
+
+       prev_backlog = sch->qstats.backlog;
+       fq_codel_drop(sch);
+       return prev_backlog - sch->qstats.backlog;
+}
+
 static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
@@ -279,10 +288,26 @@ begin:
 
 static void fq_codel_reset(struct Qdisc *sch)
 {
-       struct sk_buff *skb;
+       struct fq_codel_sched_data *q = qdisc_priv(sch);
+       int i;
 
-       while ((skb = fq_codel_dequeue(sch)) != NULL)
-               kfree_skb(skb);
+       INIT_LIST_HEAD(&q->new_flows);
+       INIT_LIST_HEAD(&q->old_flows);
+       for (i = 0; i < q->flows_cnt; i++) {
+               struct fq_codel_flow *flow = q->flows + i;
+
+               while (flow->head) {
+                       struct sk_buff *skb = dequeue_head(flow);
+
+                       qdisc_qstats_backlog_dec(sch, skb);
+                       kfree_skb(skb);
+               }
+
+               INIT_LIST_HEAD(&flow->flowchain);
+               codel_vars_init(&flow->cvars);
+       }
+       memset(q->backlogs, 0, q->flows_cnt * sizeof(u32));
+       sch->q.qlen = 0;
 }
 
 static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
@@ -604,7 +629,7 @@ static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
        .enqueue        =       fq_codel_enqueue,
        .dequeue        =       fq_codel_dequeue,
        .peek           =       qdisc_peek_dequeued,
-       .drop           =       fq_codel_drop,
+       .drop           =       fq_codel_qdisc_drop,
        .init           =       fq_codel_init,
        .reset          =       fq_codel_reset,
        .destroy        =       fq_codel_destroy,
index 89f8fcf73f18f6e091881cc829861285c0c8f8b7..ade9445a55abe468107f2bcb233e48da027afb4b 100644 (file)
@@ -216,6 +216,7 @@ static struct Qdisc_ops plug_qdisc_ops __read_mostly = {
        .peek        =       qdisc_peek_head,
        .init        =       plug_init,
        .change      =       plug_change,
+       .reset       =       qdisc_reset_queue,
        .owner       =       THIS_MODULE,
 };
 
index 7d14926633601b85c2d281d914fa978c8a038e10..52f75a5473e120f8d0a02a2ff1c0215ff02437b5 100644 (file)
@@ -306,10 +306,10 @@ drop:
                len = qdisc_pkt_len(skb);
                slot->backlog -= len;
                sfq_dec(q, x);
-               kfree_skb(skb);
                sch->q.qlen--;
                qdisc_qstats_drop(sch);
                qdisc_qstats_backlog_dec(sch, skb);
+               kfree_skb(skb);
                return len;
        }
 
index 1425ec2bbd5ae359a8e0408a89a6da6bb60bd87e..17bef01b9aa3e7f75328d39fc976f9e80d641e92 100644 (file)
@@ -2200,12 +2200,6 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
        if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))
                return -EFAULT;
 
-       if (sctp_sk(sk)->subscribe.sctp_data_io_event)
-               pr_warn_ratelimited(DEPRECATED "%s (pid %d) "
-                                   "Requested SCTP_SNDRCVINFO event.\n"
-                                   "Use SCTP_RCVINFO through SCTP_RECVRCVINFO option instead.\n",
-                                   current->comm, task_pid_nr(current));
-
        /* At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT,
         * if there is no data to be sent or retransmit, the stack will
         * immediately send up this notification.
index 9825ff0f91d6c0bde819105f639cae21883bbfad..6255d141133bb0ccabc195c8b4d9bce8cbe39c51 100644 (file)
@@ -240,8 +240,8 @@ static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid)
                req = xprt_alloc_bc_req(xprt, GFP_ATOMIC);
                if (!req)
                        goto not_found;
-               /* Note: this 'free' request adds it to xprt->bc_pa_list */
-               xprt_free_bc_request(req);
+               list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
+               xprt->bc_alloc_count++;
        }
        req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
                                rq_bc_pa_list);
@@ -336,7 +336,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
 
        spin_lock(&xprt->bc_pa_lock);
        list_del(&req->rq_bc_pa_list);
-       xprt->bc_alloc_count--;
+       xprt_dec_alloc_count(xprt, 1);
        spin_unlock(&xprt->bc_pa_lock);
 
        req->rq_private_buf.len = copied;
index cbc6af923dd1cb0baabc95161989133150269d4f..23608eb0ded2c94e363ed06e35384b08417e04ed 100644 (file)
@@ -1902,6 +1902,7 @@ call_transmit_status(struct rpc_task *task)
 
        switch (task->tk_status) {
        case -EAGAIN:
+       case -ENOBUFS:
                break;
        default:
                dprint_status(task);
@@ -1928,7 +1929,6 @@ call_transmit_status(struct rpc_task *task)
        case -ECONNABORTED:
        case -EADDRINUSE:
        case -ENOTCONN:
-       case -ENOBUFS:
        case -EPIPE:
                rpc_task_force_reencode(task);
        }
@@ -2057,12 +2057,13 @@ call_status(struct rpc_task *task)
        case -ECONNABORTED:
                rpc_force_rebind(clnt);
        case -EADDRINUSE:
-       case -ENOBUFS:
                rpc_delay(task, 3*HZ);
        case -EPIPE:
        case -ENOTCONN:
                task->tk_action = call_bind;
                break;
+       case -ENOBUFS:
+               rpc_delay(task, HZ>>2);
        case -EAGAIN:
                task->tk_action = call_transmit;
                break;
index e193c2b5476b3a83973e9799e2e826fdcd2b842c..0030376327b77f0a08d4af887286a0616a60069e 100644 (file)
@@ -527,6 +527,10 @@ static int xs_local_send_request(struct rpc_task *task)
                              true, &sent);
        dprintk("RPC:       %s(%u) = %d\n",
                        __func__, xdr->len - req->rq_bytes_sent, status);
+
+       if (status == -EAGAIN && sock_writeable(transport->inet))
+               status = -ENOBUFS;
+
        if (likely(sent > 0) || status == 0) {
                req->rq_bytes_sent += sent;
                req->rq_xmit_bytes_sent += sent;
@@ -539,6 +543,7 @@ static int xs_local_send_request(struct rpc_task *task)
 
        switch (status) {
        case -ENOBUFS:
+               break;
        case -EAGAIN:
                status = xs_nospace(task);
                break;
@@ -589,6 +594,9 @@ static int xs_udp_send_request(struct rpc_task *task)
        if (status == -EPERM)
                goto process_status;
 
+       if (status == -EAGAIN && sock_writeable(transport->inet))
+               status = -ENOBUFS;
+
        if (sent > 0 || status == 0) {
                req->rq_xmit_bytes_sent += sent;
                if (sent >= req->rq_slen)
@@ -669,9 +677,6 @@ static int xs_tcp_send_request(struct rpc_task *task)
                dprintk("RPC:       xs_tcp_send_request(%u) = %d\n",
                                xdr->len - req->rq_bytes_sent, status);
 
-               if (unlikely(sent == 0 && status < 0))
-                       break;
-
                /* If we've sent the entire packet, immediately
                 * reset the count of bytes sent. */
                req->rq_bytes_sent += sent;
@@ -681,18 +686,21 @@ static int xs_tcp_send_request(struct rpc_task *task)
                        return 0;
                }
 
-               if (sent != 0)
-                       continue;
-               status = -EAGAIN;
-               break;
+               if (status < 0)
+                       break;
+               if (sent == 0) {
+                       status = -EAGAIN;
+                       break;
+               }
        }
+       if (status == -EAGAIN && sk_stream_is_writeable(transport->inet))
+               status = -ENOBUFS;
 
        switch (status) {
        case -ENOTSOCK:
                status = -ENOTCONN;
                /* Should we call xs_close() here? */
                break;
-       case -ENOBUFS:
        case -EAGAIN:
                status = xs_nospace(task);
                break;
@@ -703,6 +711,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
        case -ECONNREFUSED:
        case -ENOTCONN:
        case -EADDRINUSE:
+       case -ENOBUFS:
        case -EPIPE:
                clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
        }
index 84f77a0540251cbe127785de670e5b0a41a3bdac..9f2add3cba26e54eadc15aeea05c3db167a75665 100644 (file)
@@ -171,8 +171,10 @@ int switchdev_port_attr_set(struct net_device *dev, struct switchdev_attr *attr)
                 * released.
                 */
 
-               attr->trans = SWITCHDEV_TRANS_ABORT;
-               __switchdev_port_attr_set(dev, attr);
+               if (err != -EOPNOTSUPP) {
+                       attr->trans = SWITCHDEV_TRANS_ABORT;
+                       __switchdev_port_attr_set(dev, attr);
+               }
 
                return err;
        }
@@ -249,8 +251,10 @@ int switchdev_port_obj_add(struct net_device *dev, struct switchdev_obj *obj)
                 * released.
                 */
 
-               obj->trans = SWITCHDEV_TRANS_ABORT;
-               __switchdev_port_obj_add(dev, obj);
+               if (err != -EOPNOTSUPP) {
+                       obj->trans = SWITCHDEV_TRANS_ABORT;
+                       __switchdev_port_obj_add(dev, obj);
+               }
 
                return err;
        }
index 46b6ed534ef224e5e1049b34eb9ebe34c27b383d..3a7567f690f35458f0fe58e0cc1254a4ec8033fa 100644 (file)
@@ -2007,6 +2007,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
        res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1);
        if (res)
                goto exit;
+       security_sk_clone(sock->sk, new_sock->sk);
 
        new_sk = new_sock->sk;
        new_tsock = tipc_sk(new_sk);
index 915b328b9ac5e71afe3a979640288ad2bfab4a22..59cabc9bce693f5f39f1d2db8f436a18ac2efcaa 100644 (file)
@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
        return false;
 }
 
-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
-                            struct cfg80211_chan_def *chandef,
-                            enum nl80211_iftype iftype)
+static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
+                                    struct cfg80211_chan_def *chandef,
+                                    enum nl80211_iftype iftype,
+                                    bool check_no_ir)
 {
        bool res;
        u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
                               IEEE80211_CHAN_RADAR;
 
-       trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
+       trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
 
-       /*
-        * Under certain conditions suggested by some regulatory bodies a
-        * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
-        * only if such relaxations are not enabled and the conditions are not
-        * met.
-        */
-       if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
+       if (check_no_ir)
                prohibited_flags |= IEEE80211_CHAN_NO_IR;
 
        if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
        trace_cfg80211_return_bool(res);
        return res;
 }
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+                            struct cfg80211_chan_def *chandef,
+                            enum nl80211_iftype iftype)
+{
+       return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
+}
 EXPORT_SYMBOL(cfg80211_reg_can_beacon);
 
+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+                                  struct cfg80211_chan_def *chandef,
+                                  enum nl80211_iftype iftype)
+{
+       bool check_no_ir;
+
+       ASSERT_RTNL();
+
+       /*
+        * Under certain conditions suggested by some regulatory bodies a
+        * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
+        * only if such relaxations are not enabled and the conditions are not
+        * met.
+        */
+       check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
+                                                  chandef->chan);
+
+       return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
+}
+EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
+
 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
                                 struct cfg80211_chan_def *chandef)
 {
index c264effd00a69f97654e9a53959414321ea01668..76b41578a838e3bed8596c5950ffbd6881d54a64 100644 (file)
@@ -2003,7 +2003,8 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
        switch (iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
-               if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
+               if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+                                                  iftype)) {
                        result = -EINVAL;
                        break;
                }
@@ -3403,8 +3404,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        } else if (!nl80211_get_ap_channel(rdev, &params))
                return -EINVAL;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
-                                    wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
@@ -6492,8 +6493,8 @@ skip_beacons:
        if (err)
                return err;
 
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
-                                    wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        err = cfg80211_chandef_dfs_required(wdev->wiphy,
@@ -10170,7 +10171,8 @@ static int nl80211_tdls_channel_switch(struct sk_buff *skb,
                return -EINVAL;
 
        /* we will be active on the TDLS link */
-       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
+       if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
+                                          wdev->iftype))
                return -EINVAL;
 
        /* don't allow switching to DFS channels */
index d359e0610198c5c3d2094120e4ba3cf714d8dc21..aa2d75482017e1a258eb0cdb7271b2d615d8782e 100644 (file)
@@ -544,15 +544,15 @@ static int call_crda(const char *alpha2)
        reg_regdb_query(alpha2);
 
        if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
-               pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n");
+               pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n");
                return -EINVAL;
        }
 
        if (!is_world_regdom((char *) alpha2))
-               pr_info("Calling CRDA for country: %c%c\n",
+               pr_debug("Calling CRDA for country: %c%c\n",
                        alpha2[0], alpha2[1]);
        else
-               pr_info("Calling CRDA to update world regulatory domain\n");
+               pr_debug("Calling CRDA to update world regulatory domain\n");
 
        return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
 }
@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
+               return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
                return cfg80211_chandef_usable(wiphy, &chandef,
index af3617c9879e33f8be5c325ffdc3b5558e60b217..a808279a432a9ef1a23976ba169ac33ba377fe6d 100644 (file)
@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
 
 TRACE_EVENT(cfg80211_reg_can_beacon,
        TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
-                enum nl80211_iftype iftype),
-       TP_ARGS(wiphy, chandef, iftype),
+                enum nl80211_iftype iftype, bool check_no_ir),
+       TP_ARGS(wiphy, chandef, iftype, check_no_ir),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                CHAN_DEF_ENTRY
                __field(enum nl80211_iftype, iftype)
+               __field(bool, check_no_ir)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                CHAN_DEF_ASSIGN(chandef);
                __entry->iftype = iftype;
+               __entry->check_no_ir = check_no_ir;
        ),
-       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
-                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
+                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
+                 BOOL_TO_STR(__entry->check_no_ir))
 );
 
 TRACE_EVENT(cfg80211_chandef_dfs_required,
index 8965d1bb881194685d1af344cbdfd2868c2aa9fd..125d6402f64f8555ec85b42f4c39e3af0f46ef3b 100644 (file)
  *
  *      For __dynamic_array(int, foo, bar) use __get_dynamic_array(foo)
  *            Use __get_dynamic_array_len(foo) to get the length of the array
- *            saved.
+ *            saved. Note, __get_dynamic_array_len() returns the total allocated
+ *            length of the dynamic array; __print_array() expects the second
+ *            parameter to be the number of elements. To get that, the array length
+ *            needs to be divided by the element size.
  *
  *      For __string(foo, bar) use __get_str(foo)
  *
@@ -288,7 +291,7 @@ TRACE_EVENT(foo_bar,
  *    This prints out the array that is defined by __array in a nice format.
  */
                  __print_array(__get_dynamic_array(list),
-                               __get_dynamic_array_len(list),
+                               __get_dynamic_array_len(list) / sizeof(int),
                                sizeof(int)),
                  __get_str(str), __get_bitmask(cpus))
 );
index 90e1edc8dd42fbfba3c31d03214f99d4e3c361b4..d5c8e9a3a73cfc1450b7c698e10aa9848a01dad2 100755 (executable)
@@ -2599,7 +2599,7 @@ sub process {
 # if LONG_LINE is ignored, the other 2 types are also ignored
 #
 
-               if ($length > $max_line_length) {
+               if ($line =~ /^\+/ && $length > $max_line_length) {
                        my $msg_type = "LONG_LINE";
 
                        # Check the allowed long line types first
index 9cb8522d8d22a826caaec968e82c77516339ca01..f3d3fb42b8735e76aa54bd4c433574f7afc43b0e 100755 (executable)
@@ -137,7 +137,7 @@ my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
 my $kconfig = $ARGV[1];
 my $lsmod_file = $ENV{'LSMOD'};
 
-my @makefiles = `find $ksource -name Makefile 2>/dev/null`;
+my @makefiles = `find $ksource -name Makefile -or -name Kbuild 2>/dev/null`;
 chomp @makefiles;
 
 my %depends;
index eff7de1fc82ee890e5a8f51695ee5a5751aa80f8..e70fcd12eeebe813bafd7e56f014bcf5b4e33647 100644 (file)
@@ -63,6 +63,8 @@ int main(void)
 
        DEVID(acpi_device_id);
        DEVID_FIELD(acpi_device_id, id);
+       DEVID_FIELD(acpi_device_id, cls);
+       DEVID_FIELD(acpi_device_id, cls_msk);
 
        DEVID(pnp_device_id);
        DEVID_FIELD(pnp_device_id, id);
index 84c86f3cd6cdc1b44b53b7a60b066dd6972b2b96..5f208820913259651246d71a3def44f49fa8da44 100644 (file)
@@ -523,12 +523,40 @@ static int do_serio_entry(const char *filename,
 }
 ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry);
 
-/* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */
+/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or
+ *             "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if)
+ *
+ * NOTE: Each driver should use one of the following : _HID, _CIDs
+ *       or _CLS. Also, bb, ss, and pp can be substituted with ??
+ *       as don't care byte.
+ */
 static int do_acpi_entry(const char *filename,
                        void *symval, char *alias)
 {
        DEF_FIELD_ADDR(symval, acpi_device_id, id);
-       sprintf(alias, "acpi*:%s:*", *id);
+       DEF_FIELD_ADDR(symval, acpi_device_id, cls);
+       DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk);
+
+       if (id && strlen((const char *)*id))
+               sprintf(alias, "acpi*:%s:*", *id);
+       else if (cls) {
+               int i, byte_shift, cnt = 0;
+               unsigned int msk;
+
+               sprintf(&alias[cnt], "acpi*:");
+               cnt = 6;
+               for (i = 1; i <= 3; i++) {
+                       byte_shift = 8 * (3-i);
+                       msk = (*cls_msk >> byte_shift) & 0xFF;
+                       if (msk)
+                               sprintf(&alias[cnt], "%02x",
+                                       (*cls >> byte_shift) & 0xFF);
+                       else
+                               sprintf(&alias[cnt], "??");
+                       cnt += 2;
+               }
+               sprintf(&alias[cnt], ":*");
+       }
        return 1;
 }
 ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry);
index 91ee1b2e0f9aa65fbdcb471d8f6695489453029f..12d3db3bd46b491542090cd2db01637754467e99 100644 (file)
@@ -886,7 +886,8 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
                ".kprobes.text"
 #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
-               ".fixup", ".entry.text", ".exception.text", ".text.*"
+               ".fixup", ".entry.text", ".exception.text", ".text.*", \
+               ".coldtext"
 
 #define INIT_SECTIONS      ".init.*"
 #define MEM_INIT_SECTIONS  ".meminit.*"
index e72548b5897ec237dd7463374871538c81a84fd7..d33437007ad229313a5ef483826e427a74350876 100644 (file)
@@ -1181,9 +1181,11 @@ void __key_link_end(struct key *keyring,
        if (index_key->type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 
-       if (edit && !edit->dead_leaf) {
-               key_payload_reserve(keyring,
-                                   keyring->datalen - KEYQUOTA_LINK_BYTES);
+       if (edit) {
+               if (!edit->dead_leaf) {
+                       key_payload_reserve(keyring,
+                               keyring->datalen - KEYQUOTA_LINK_BYTES);
+               }
                assoc_array_cancel_edit(edit);
        }
        up_write(&keyring->sem);
index 62310819964145eb800adea251122a2298c8d532..564079c5c49dce530f56fd0626827d81c0ec75d4 100644 (file)
@@ -3283,7 +3283,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
        int rc = 0;
 
        if (default_noexec &&
-           (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
+           (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
+                                  (!shared && (prot & PROT_WRITE)))) {
                /*
                 * We are making executable an anonymous mapping or a
                 * private file mapping that will also be writable.
index afe6a269ec177897d3a8851ae2e3cddf19688bce..57644b1dc42e1a38b5f1fd0d24ab75164b3bdbf1 100644 (file)
@@ -153,6 +153,12 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
                if (offset == (u32)-1)
                        return 0;
 
+               /* don't waste ebitmap space if the netlabel bitmap is empty */
+               if (bitmap == 0) {
+                       offset += EBITMAP_UNIT_SIZE;
+                       continue;
+               }
+
                if (e_iter == NULL ||
                    offset >= e_iter->startbit + EBITMAP_SIZE) {
                        e_prev = e_iter;
index 9ed32502470e9bc1d776d5d925ee48be587baa17..5ebb8968793670d6a23ee6e6d2b30df6243a63ca 100644 (file)
@@ -406,6 +406,7 @@ static __init int yama_init(void)
         */
        if (!security_module_enable("yama"))
                return 0;
+       yama_add_hooks();
 #endif
        pr_info("Yama: becoming mindful.\n");
 
index d126c03361aef87fb1239df1e42f547c5ce36aa9..75888dd38a7fc87acf5fcd7789570ad353dce482 100644 (file)
@@ -85,7 +85,7 @@ static DECLARE_RWSEM(snd_pcm_link_rwsem);
 void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
 {
        if (substream->pcm->nonatomic) {
-               down_read(&snd_pcm_link_rwsem);
+               down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING);
                mutex_lock(&substream->self_group.mutex);
        } else {
                read_lock(&snd_pcm_link_rwlock);
index 7bb988fa6b6d17764e08f39ecbf45f31ee2ff2ee..2a153d260836704011b6eadddfbc9b463e1b37b3 100644 (file)
@@ -740,8 +740,9 @@ static int handle_in_packet(struct amdtp_stream *s,
            s->data_block_counter != UINT_MAX)
                data_block_counter = s->data_block_counter;
 
-       if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) && data_block_counter == 0) ||
-           (s->data_block_counter == UINT_MAX)) {
+       if (((s->flags & CIP_SKIP_DBC_ZERO_CHECK) &&
+            data_block_counter == s->tx_first_dbc) ||
+           s->data_block_counter == UINT_MAX) {
                lost = false;
        } else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
                lost = data_block_counter != s->data_block_counter;
index 26b909329e54d96d7fcb075f9538599aaf30cb09..b2cf9e75693b643ce0ac81ebdef15458fd2d4018 100644 (file)
@@ -157,6 +157,8 @@ struct amdtp_stream {
 
        /* quirk: fixed interval of dbc between previos/current packets. */
        unsigned int tx_dbc_interval;
+       /* quirk: indicate the value of dbc field in a first packet. */
+       unsigned int tx_first_dbc;
 
        bool callbacked;
        wait_queue_head_t callback_wait;
index 2682e7e3e5c98511e8bd26fddf452427f1e83a6a..c94a432f7cc653dca45316ea67bdc481b9e8e887 100644 (file)
@@ -248,8 +248,16 @@ efw_probe(struct fw_unit *unit,
        err = get_hardware_info(efw);
        if (err < 0)
                goto error;
+       /* AudioFire8 (since 2009) and AudioFirePre8 */
        if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9)
                efw->is_af9 = true;
+       /* These models uses the same firmware. */
+       if (entry->model_id == MODEL_ECHO_AUDIOFIRE_2 ||
+           entry->model_id == MODEL_ECHO_AUDIOFIRE_4 ||
+           entry->model_id == MODEL_ECHO_AUDIOFIRE_9 ||
+           entry->model_id == MODEL_GIBSON_RIP ||
+           entry->model_id == MODEL_GIBSON_GOLDTOP)
+               efw->is_fireworks3 = true;
 
        snd_efw_proc_init(efw);
 
index 4f0201a95222a2502ec438199fe9e78cad33b647..084d414b228cf425dc99440cc081d65459bbe175 100644 (file)
@@ -71,6 +71,7 @@ struct snd_efw {
 
        /* for quirks */
        bool is_af9;
+       bool is_fireworks3;
        u32 firmware_version;
 
        unsigned int midi_in_ports;
index c55db1bddc80a0ceab4997279643f73840943cef..7e353f1f7bff359ea8845630aeff2521759e508f 100644 (file)
@@ -172,6 +172,15 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
        efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT;
        /* Fireworks reset dbc at bus reset. */
        efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK;
+       /*
+        * But Recent firmwares starts packets with non-zero dbc.
+        * Driver version 5.7.6 installs firmware version 5.7.3.
+        */
+       if (efw->is_fireworks3 &&
+           (efw->firmware_version == 0x5070000 ||
+            efw->firmware_version == 0x5070300 ||
+            efw->firmware_version == 0x5080000))
+               efw->tx_stream.tx_first_dbc = 0x02;
        /* AudioFire9 always reports wrong dbs. */
        if (efw->is_af9)
                efw->tx_stream.flags |= CIP_WRONG_DBS;
index b2da19b60f4e25cf6ec858832d6f33349313ca66..358f16195483f6b51c3a84a3cff672d8696951a6 100644 (file)
@@ -44,16 +44,10 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus)
 
        offset = snd_hdac_chip_readl(bus, LLCH);
 
-       if (offset < 0)
-               return -EIO;
-
        /* Lets walk the linked capabilities list */
        do {
                cur_cap = _snd_hdac_chip_read(l, bus, offset);
 
-               if (cur_cap < 0)
-                       return -EIO;
-
                dev_dbg(bus->dev, "Capability version: 0x%x\n",
                                ((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF));
 
index f8ffbdbb450d785e281bd7a0aae3c6d8a8c2a2ab..3de47dd1a76d856f95c2051b1bde6e55522f2b55 100644 (file)
@@ -299,7 +299,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
                if (stream->direction != substream->stream)
                        continue;
 
-               if (stream->opened) {
+               if (!stream->opened) {
                        if (!hstream->decoupled)
                                snd_hdac_ext_stream_decouple(ebus, hstream, true);
                        res = hstream;
index 442500e06b7c7b66be05ec254a68e58d009089fe..5676b849379d43468267e8d12fc7367096a2ae4c 100644 (file)
@@ -56,8 +56,11 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
                enable ? "enable" : "disable");
 
        if (enable) {
-               if (!bus->i915_power_refcount++)
+               if (!bus->i915_power_refcount++) {
                        acomp->ops->get_power(acomp->dev);
+                       snd_hdac_set_codec_wakeup(bus, true);
+                       snd_hdac_set_codec_wakeup(bus, false);
+               }
        } else {
                WARN_ON(!bus->i915_power_refcount);
                if (!--bus->i915_power_refcount)
index ac0db1679f098ee4ec08c6770fe1f1374c8bf431..b077bb644434734004b7afca348bbac4643478a5 100644 (file)
@@ -5175,7 +5175,7 @@ static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
        int err = 0;
 
        mutex_lock(&spec->pcm_mutex);
-       if (!spec->indep_hp_enabled)
+       if (spec->indep_hp && !spec->indep_hp_enabled)
                err = -EBUSY;
        else
                spec->active_streams |= 1 << STREAM_INDEP_HP;
index 745535d1840a6713e802aaa8c1d475733b88720e..c38c68f579381d657786945baa3ab99b3ccae787 100644 (file)
@@ -867,7 +867,7 @@ static int azx_suspend(struct device *dev)
 
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
-       if (chip->disabled || hda->init_failed)
+       if (chip->disabled || hda->init_failed || !chip->running)
                return 0;
 
        bus = azx_bus(chip);
@@ -902,7 +902,7 @@ static int azx_resume(struct device *dev)
 
        chip = card->private_data;
        hda = container_of(chip, struct hda_intel, chip);
-       if (chip->disabled || hda->init_failed)
+       if (chip->disabled || hda->init_failed || !chip->running)
                return 0;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
@@ -979,14 +979,16 @@ static int azx_runtime_resume(struct device *dev)
        if (!azx_has_pm_runtime(chip))
                return 0;
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
-               && hda->need_i915_power) {
-               bus =  azx_bus(chip);
-               snd_hdac_display_power(bus, true);
-               haswell_set_bclk(hda);
-               /* toggle codec wakeup bit for STATESTS read */
-               snd_hdac_set_codec_wakeup(bus, true);
-               snd_hdac_set_codec_wakeup(bus, false);
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+               bus = azx_bus(chip);
+               if (hda->need_i915_power) {
+                       snd_hdac_display_power(bus, true);
+                       haswell_set_bclk(hda);
+               } else {
+                       /* toggle codec wakeup bit for STATESTS read */
+                       snd_hdac_set_codec_wakeup(bus, true);
+                       snd_hdac_set_codec_wakeup(bus, false);
+               }
        }
 
        /* Read STATESTS before controller reset */
@@ -1025,7 +1027,7 @@ static int azx_runtime_idle(struct device *dev)
                return 0;
 
        if (!power_save_controller || !azx_has_pm_runtime(chip) ||
-           azx_bus(chip)->codec_powered)
+           azx_bus(chip)->codec_powered || !chip->running)
                return -EBUSY;
 
        return 0;
@@ -2182,6 +2184,8 @@ static const struct pci_device_id azx_ids[] = {
        /* ATI HDMI */
        { PCI_DEVICE(0x1002, 0x1308),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0x157a),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0x793b),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
        { PCI_DEVICE(0x1002, 0x7919),
@@ -2236,8 +2240,14 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaab0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaac0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        { PCI_DEVICE(0x1002, 0xaac8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaad8),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+       { PCI_DEVICE(0x1002, 0xaae8),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
        /* VIA VT8251/VT8237A */
        { PCI_DEVICE(0x1106, 0x3288),
          .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
index 25ccf781fbe705cb5b2980814f7d4f90aff2d4a6..584a0343ab0cc132b7c2038679923b6617926cf7 100644 (file)
@@ -999,9 +999,7 @@ static void cs4210_spdif_automute(struct hda_codec *codec,
 
        spec->spdif_present = spdif_present;
        /* SPDIF TX on/off */
-       if (spdif_present)
-               snd_hda_set_pin_ctl(codec, spdif_pin,
-                                   spdif_present ? PIN_OUT : 0);
+       snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
 
        cs_automute(codec);
 }
index 2f2433845d0487dd703301664cbc33ecfc77bc11..a97db5fc8a151aa43c0c99edc6ccf7efc0eaa52a 100644 (file)
@@ -3512,6 +3512,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de0070, .name = "GPU 70 HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de0071, .name = "GPU 71 HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de0072, .name = "GPU 72 HDMI/DP",  .patch = patch_nvhdmi },
+{ .id = 0x10de007d, .name = "GPU 7d HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
 { .id = 0x11069f80, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
 { .id = 0x11069f81, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
@@ -3527,6 +3528,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x80862807, .name = "Haswell HDMI",    .patch = patch_generic_hdmi },
 { .id = 0x80862808, .name = "Broadwell HDMI",  .patch = patch_generic_hdmi },
 { .id = 0x80862809, .name = "Skylake HDMI",    .patch = patch_generic_hdmi },
+{ .id = 0x8086280a, .name = "Broxton HDMI",    .patch = patch_generic_hdmi },
 { .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
 { .id = 0x80862882, .name = "Valleyview2 HDMI",        .patch = patch_generic_hdmi },
 { .id = 0x80862883, .name = "Braswell HDMI",   .patch = patch_generic_hdmi },
@@ -3575,6 +3577,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0067");
 MODULE_ALIAS("snd-hda-codec-id:10de0070");
 MODULE_ALIAS("snd-hda-codec-id:10de0071");
 MODULE_ALIAS("snd-hda-codec-id:10de0072");
+MODULE_ALIAS("snd-hda-codec-id:10de007d");
 MODULE_ALIAS("snd-hda-codec-id:10de8001");
 MODULE_ALIAS("snd-hda-codec-id:11069f80");
 MODULE_ALIAS("snd-hda-codec-id:11069f81");
@@ -3591,6 +3594,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862806");
 MODULE_ALIAS("snd-hda-codec-id:80862807");
 MODULE_ALIAS("snd-hda-codec-id:80862808");
 MODULE_ALIAS("snd-hda-codec-id:80862809");
+MODULE_ALIAS("snd-hda-codec-id:8086280a");
 MODULE_ALIAS("snd-hda-codec-id:80862880");
 MODULE_ALIAS("snd-hda-codec-id:80862882");
 MODULE_ALIAS("snd-hda-codec-id:80862883");
index b3b44681d3cfbe90b2ff7bcbabba735dcfaac7f7..374ea53288ca25ff6093467012afd2607192f505 100644 (file)
@@ -2222,7 +2222,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
        SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
 
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
@@ -4441,6 +4441,55 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec,
        }
 }
 
+/* Hook to update amp GPIO4 for automute */
+static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
+                                         struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+
+       snd_hda_gen_hp_automute(codec, jack);
+       /* mute_led_polarity is set to 0, so we pass inverted value here */
+       alc_update_gpio_led(codec, 0x10, !spec->gen.hp_jack_present);
+}
+
+/* Manage GPIOs for HP EliteBook Folio 9480m.
+ *
+ * GPIO4 is the headphone amplifier power control
+ * GPIO3 is the audio output mute indicator LED
+ */
+
+static void alc280_fixup_hp_9480m(struct hda_codec *codec,
+                                 const struct hda_fixup *fix,
+                                 int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
+               {}
+       };
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* Set the hooks to turn the headphone amp on/off
+                * as needed
+                */
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+               spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook;
+
+               /* The GPIOs are currently off */
+               spec->gpio_led = 0;
+
+               /* GPIO3 is connected to the output mute LED,
+                * high is on, low is off
+                */
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x08;
+
+               /* Initialize GPIO configuration */
+               snd_hda_add_verbs(codec, gpio_init);
+       }
+}
+
 /* for hda_fixup_thinkpad_acpi() */
 #include "thinkpad_helper.c"
 
@@ -4521,6 +4570,7 @@ enum {
        ALC286_FIXUP_HP_GPIO_LED,
        ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
        ALC280_FIXUP_HP_DOCK_PINS,
+       ALC280_FIXUP_HP_9480M,
        ALC288_FIXUP_DELL_HEADSET_MODE,
        ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
        ALC288_FIXUP_DELL_XPS_13_GPIO6,
@@ -5011,7 +5061,7 @@ static const struct hda_fixup alc269_fixups[] = {
                        { 0x14, 0x90170110 },
                        { 0x17, 0x40000008 },
                        { 0x18, 0x411111f0 },
-                       { 0x19, 0x411111f0 },
+                       { 0x19, 0x01a1913c },
                        { 0x1a, 0x411111f0 },
                        { 0x1b, 0x411111f0 },
                        { 0x1d, 0x40f89b2d },
@@ -5043,6 +5093,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC280_FIXUP_HP_GPIO4
        },
+       [ALC280_FIXUP_HP_9480M] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc280_fixup_hp_9480m,
+       },
        [ALC288_FIXUP_DELL_HEADSET_MODE] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_headset_mode_dell_alc288,
@@ -5131,9 +5185,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13),
+       SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK),
        SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
+       SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5161,6 +5218,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M),
        SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
        /* ALC290 */
@@ -5234,6 +5292,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5343,8 +5402,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x19, 0x411111f0}, \
        {0x1a, 0x411111f0}, \
        {0x1b, 0x411111f0}, \
-       {0x1d, 0x40700001}, \
-       {0x1e, 0x411111f0}, \
        {0x21, 0x02211020}
 
 #define ALC282_STANDARD_PINS \
@@ -5375,8 +5432,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x15, 0x0221401f}, \
        {0x1a, 0x411111f0}, \
        {0x1b, 0x411111f0}, \
-       {0x1d, 0x40700001}, \
-       {0x1e, 0x411111f0}
+       {0x1d, 0x40700001}
 
 #define ALC298_STANDARD_PINS \
        {0x18, 0x411111f0}, \
@@ -5407,6 +5463,39 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x17, 0x40000000},
                {0x1d, 0x40700001},
                {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x40000000},
+               {0x14, 0x90170130},
+               {0x17, 0x411111f0},
+               {0x18, 0x411111f0},
+               {0x19, 0x411111f0},
+               {0x1a, 0x411111f0},
+               {0x1b, 0x01014020},
+               {0x1d, 0x4054c029},
+               {0x1e, 0x411111f0},
+               {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x40000000},
+               {0x14, 0x90170150},
+               {0x17, 0x411111f0},
+               {0x18, 0x411111f0},
+               {0x19, 0x411111f0},
+               {0x1a, 0x411111f0},
+               {0x1b, 0x02011020},
+               {0x1d, 0x4054c029},
+               {0x1e, 0x411111f0},
+               {0x21, 0x0221105f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x40000000},
+               {0x14, 0x90170110},
+               {0x17, 0x411111f0},
+               {0x18, 0x411111f0},
+               {0x19, 0x411111f0},
+               {0x1a, 0x411111f0},
+               {0x1b, 0x01014020},
+               {0x1d, 0x4054c029},
+               {0x1e, 0x411111f0},
+               {0x21, 0x0221101f}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                {0x12, 0x90a60160},
                {0x14, 0x90170120},
@@ -5469,10 +5558,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x21, 0x02211030}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS,
-               {0x13, 0x40000000}),
+               {0x13, 0x40000000},
+               {0x1d, 0x40700001},
+               {0x1e, 0x411111f0}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC256_STANDARD_PINS,
+               {0x13, 0x411111f0},
+               {0x1d, 0x40700001},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS,
-               {0x13, 0x411111f0}),
+               {0x13, 0x411111f0},
+               {0x1d, 0x4077992d},
+               {0x1e, 0x411111ff}),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
                {0x13, 0x40000000},
@@ -5635,35 +5733,48 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x13, 0x411111f0},
                {0x16, 0x01014020},
                {0x18, 0x411111f0},
-               {0x19, 0x01a19030}),
+               {0x19, 0x01a19030},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x90a60140},
                {0x13, 0x411111f0},
                {0x16, 0x01014020},
                {0x18, 0x02a19031},
-               {0x19, 0x01a1903e}),
+               {0x19, 0x01a1903e},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x90a60140},
                {0x13, 0x411111f0},
                {0x16, 0x411111f0},
                {0x18, 0x411111f0},
-               {0x19, 0x411111f0}),
+               {0x19, 0x411111f0},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x40000000},
                {0x13, 0x90a60140},
                {0x16, 0x21014020},
                {0x18, 0x411111f0},
-               {0x19, 0x21a19030}),
+               {0x19, 0x21a19030},
+               {0x1e, 0x411111f0}),
        SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC292_STANDARD_PINS,
                {0x12, 0x40000000},
                {0x13, 0x90a60140},
                {0x16, 0x411111f0},
                {0x18, 0x411111f0},
-               {0x19, 0x411111f0}),
+               {0x19, 0x411111f0},
+               {0x1e, 0x411111f0}),
+       SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x40000000},
+               {0x13, 0x90a60140},
+               {0x16, 0x21014020},
+               {0x18, 0x411111f0},
+               {0x19, 0x21a19030},
+               {0x1e, 0x411111ff}),
        SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC298_STANDARD_PINS,
                {0x12, 0x90a60130},
index dcc7fe91244c2dfada5c97fbb42df06dbd857bbf..9d947aef2c8b60b99f63fd9464ad289bef0c7061 100644 (file)
@@ -2920,7 +2920,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a,
                      "HP Mini", STAC_92HD83XXX_HP_LED),
        SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_TOSHIBA, 0xfa91,
+       /* match both for 0xfa91 and 0xfa93 */
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_TOSHIBA, 0xfffd, 0xfa91,
                      "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD),
        {} /* terminator */
 };
index 6492bca8c70f8bbfdf31e2fb13321904f5a5b00a..4ca12665ff730c6980e2a4366dd195e47f94aecd 100644 (file)
@@ -88,7 +88,7 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
        int changed;
 
        mutex_lock(&chip->mutex);
-       changed = !value->value.integer.value[0] != chip->dac_mute;
+       changed = (!value->value.integer.value[0]) != chip->dac_mute;
        if (changed) {
                chip->dac_mute = !value->value.integer.value[0];
                chip->model.update_dac_mute(chip);
index 2ae9619443d15dbeaf128cab385347db6bf26369..1d651b8a89570404cd306f239b17e939b1d5fa81 100644 (file)
@@ -30,6 +30,9 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
        bool
        select SND_DMAENGINE_PCM
 
+config SND_SOC_TOPOLOGY
+       bool
+
 # All the supported SoCs
 source "sound/soc/adi/Kconfig"
 source "sound/soc/atmel/Kconfig"
index e189903fabf42958eff143e487999f0f013b85d7..669648b41d3027adf29ead27eda5f72a6ed0aaf1 100644 (file)
@@ -1,6 +1,9 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
+
+ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
 snd-soc-core-objs += soc-topology.o
+endif
 
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
index d7ec4756e45bf9bab0c08059ee74c39b4ea3c812..8e36198474d94d59cd8b7bda10e6be434103fa55 100644 (file)
@@ -457,14 +457,14 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
        case SND_SOC_DAIFMT_RIGHT_J:
                if (params_width(params) == 16) {
                        snd_soc_update_bits(codec, CS4265_DAC_CTL,
-                               CS4265_DAC_CTL_DIF, (1 << 5));
+                               CS4265_DAC_CTL_DIF, (2 << 4));
                        snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
-                               CS4265_SPDIF_CTL2_DIF, (1 << 7));
+                               CS4265_SPDIF_CTL2_DIF, (2 << 6));
                } else {
                        snd_soc_update_bits(codec, CS4265_DAC_CTL,
-                               CS4265_DAC_CTL_DIF, (3 << 5));
+                               CS4265_DAC_CTL_DIF, (3 << 4));
                        snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
-                               CS4265_SPDIF_CTL2_DIF, (1 << 7));
+                               CS4265_SPDIF_CTL2_DIF, (3 << 6));
                }
                break;
        case SND_SOC_DAIFMT_LEFT_J:
@@ -473,7 +473,7 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
                snd_soc_update_bits(codec, CS4265_ADC_CTL,
                        CS4265_ADC_DIF, 0);
                snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
-                       CS4265_SPDIF_CTL2_DIF, (1 << 6));
+                       CS4265_SPDIF_CTL2_DIF, 0);
 
                break;
        default:
index 477e13d309713e56a5a4416d054350185fea0007..e7ba557979cb2589439234d6bd0ddbbdc38985e5 100644 (file)
@@ -102,7 +102,7 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec)
 
        if (val != -1) {
                regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
-                                       PCM1681_DEEMPH_RATE_MASK, val);
+                                  PCM1681_DEEMPH_RATE_MASK, val << 3);
                enable = 1;
        } else
                enable = 0;
index 9ce311e088fc514bf8cde70dd120a3074f78bfe5..961bd7e5877ee42c3e50f7a3e2e826a1ffab9cc8 100644 (file)
@@ -2943,6 +2943,9 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645)
 {
        int val, btn_type, gpio_state = 0, report = 0;
 
+       if (!rt5645->codec)
+               return -EINVAL;
+
        switch (rt5645->pdata.jd_mode) {
        case 0: /* Not using rt5645 JD */
                if (rt5645->gpiod_hp_det) {
@@ -3338,6 +3341,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
                break;
 
        case RT5645_DMIC_DATA_GPIO5:
+               regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+                       RT5645_I2S2_DAC_PIN_MASK, RT5645_I2S2_DAC_PIN_GPIO);
                regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
                        RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
                regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
index 0353a6a273ab4ca2bd5136c28aaedee14c6e54b2..278bb9f464c4120b681c7ad5c6086df89d6de3ab 100644 (file)
 #define RT5645_GP6_PIN_SFT                     6
 #define RT5645_GP6_PIN_GPIO6                   (0x0 << 6)
 #define RT5645_GP6_PIN_DMIC2_SDA               (0x1 << 6)
+#define RT5645_I2S2_DAC_PIN_MASK               (0x1 << 4)
+#define RT5645_I2S2_DAC_PIN_SFT                        4
+#define RT5645_I2S2_DAC_PIN_I2S                        (0x0 << 4)
+#define RT5645_I2S2_DAC_PIN_GPIO               (0x1 << 4)
 #define RT5645_GP8_PIN_MASK                    (0x1 << 3)
 #define RT5645_GP8_PIN_SFT                     3
 #define RT5645_GP8_PIN_GPIO8                   (0x0 << 3)
index bd7a344bf8c517edf69af2fda9e06e08488e47e0..1c317de2617623438bd169d9ba7cb89623139794 100644 (file)
 #define SGTL5000_BIAS_CTRL_MASK                        0x000e
 #define SGTL5000_BIAS_CTRL_SHIFT               1
 #define SGTL5000_BIAS_CTRL_WIDTH               3
-#define SGTL5000_SMALL_POP                     0
+#define SGTL5000_SMALL_POP                     1
 
 /*
  * SGTL5000_CHIP_MIC_CTRL
index 938d2cb6d78bee03e809f02462b17f951f0c953a..84a4f5ad80645f2f45079ea35fe8ce19da901f09 100644 (file)
@@ -315,7 +315,13 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        if (invert_fclk)
                ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
 
-       return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1);
+       return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
+                       SSM4567_SAI_CTRL_1_BCLK |
+                       SSM4567_SAI_CTRL_1_FSYNC |
+                       SSM4567_SAI_CTRL_1_LJ |
+                       SSM4567_SAI_CTRL_1_TDM |
+                       SSM4567_SAI_CTRL_1_PDM,
+                       ctrl1);
 }
 
 static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
index c7647e066cfd76b07f6b1acd4d2a68ac04bae3bc..c0b940e2019f55f34bb53673a99a4594d7409ef3 100644 (file)
@@ -633,7 +633,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
                sub *= 100000;
                do_div(sub, freq);
 
-               if (sub < savesub) {
+               if (sub < savesub && !(i == 0 && psr == 0 && div2 == 0)) {
                        baudrate = tmprate;
                        savesub = sub;
                        pm = i;
index 3853ec2ddbc758d2c558dfcbe093d2cee59af8a1..6de5d5cd3280a92bf9d1b0ab71a5171e82a5bb0b 100644 (file)
@@ -7,4 +7,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/
 obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/
 
 # Machine support
-obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/
+obj-$(CONFIG_SND_SOC) += boards/
index 620da1d1b9e3ea4fbde293c3e98fae4c30708ac1..0e0e4d9c021ff29bdf1f19eda2827ac459e4046c 100644 (file)
 #define MIN_FRAGMENT_SIZE (50 * 1024)
 #define MAX_FRAGMENT_SIZE (1024 * 1024)
 #define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz)  (((pcm_wd_sz + 15) >> 4) << 1)
+#ifdef CONFIG_PM
+#define GET_USAGE_COUNT(dev) (atomic_read(&dev->power.usage_count))
+#else
+#define GET_USAGE_COUNT(dev) 1
+#endif
 
 int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
 {
@@ -141,15 +146,9 @@ static int sst_power_control(struct device *dev, bool state)
        int ret = 0;
        int usage_count = 0;
 
-#ifdef CONFIG_PM
-       usage_count = atomic_read(&dev->power.usage_count);
-#else
-       usage_count = 1;
-#endif
-
        if (state == true) {
                ret = pm_runtime_get_sync(dev);
-
+               usage_count = GET_USAGE_COUNT(dev);
                dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
                if (ret < 0) {
                        dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
@@ -164,6 +163,7 @@ static int sst_power_control(struct device *dev, bool state)
                        }
                }
        } else {
+               usage_count = GET_USAGE_COUNT(dev);
                dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
                return sst_pm_runtime_put(ctx);
        }
index 4c01bb43928d136c93963730f1149f9d9bf4a66b..5bbaa667bec1c608c35968c983eaeece020ad8db 100644 (file)
@@ -701,6 +701,8 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
        if (byt == NULL)
                return -ENOMEM;
 
+       byt->dev = dev;
+
        ipc = &byt->ipc;
        ipc->dev = dev;
        ipc->ops.tx_msg = byt_tx_msg;
index d604ee80eda4be715601db603181e0291cc98747..70f832114a5aeffeeb7b0cc555f8f1b91bc40665 100644 (file)
@@ -69,12 +69,12 @@ static const struct snd_soc_dapm_route cht_audio_map[] = {
        {"Headphone", NULL, "HPR"},
        {"Ext Spk", NULL, "SPKL"},
        {"Ext Spk", NULL, "SPKR"},
-       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"HiFi Playback", NULL, "ssp2 Tx"},
        {"ssp2 Tx", NULL, "codec_out0"},
        {"ssp2 Tx", NULL, "codec_out1"},
        {"codec_in0", NULL, "ssp2 Rx" },
        {"codec_in1", NULL, "ssp2 Rx" },
-       {"ssp2 Rx", NULL, "AIF1 Capture"},
+       {"ssp2 Rx", NULL, "HiFi Capture"},
 };
 
 static const struct snd_kcontrol_new cht_mc_controls[] = {
index f95f271aab0ce30412954428b426af2461438dea..f6efa9d4acadd5e056ea0a0494ed51da859fbc3a 100644 (file)
@@ -2119,6 +2119,8 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
        if (hsw == NULL)
                return -ENOMEM;
 
+       hsw->dev = dev;
+
        ipc = &hsw->ipc;
        ipc->dev = dev;
        ipc->ops.tx_msg = hsw_tx_msg;
index 4d44b5803e55206c02006b9359449df377477b6c..2d2536af141fc9157b2ecb402a969af6c808faf6 100644 (file)
@@ -103,7 +103,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
                .name = "MAX98090 Playback",
                .stream_name = "MAX98090 Playback",
                .cpu_dai_name = "DL1",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -114,7 +113,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
                .name = "MAX98090 Capture",
                .stream_name = "MAX98090 Capture",
                .cpu_dai_name = "VUL",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -125,7 +123,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
        {
                .name = "Codec",
                .cpu_dai_name = "I2S",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .no_pcm = 1,
                .codec_dai_name = "HiFi",
                .init = mt8173_max98090_init,
@@ -152,9 +149,21 @@ static struct snd_soc_card mt8173_max98090_card = {
 static int mt8173_max98090_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &mt8173_max98090_card;
-       struct device_node *codec_node;
+       struct device_node *codec_node, *platform_node;
        int ret, i;
 
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_max98090_dais[i].platform_name)
+                       continue;
+               mt8173_max98090_dais[i].platform_of_node = platform_node;
+       }
+
        codec_node = of_parse_phandle(pdev->dev.of_node,
                                      "mediatek,audio-codec", 0);
        if (!codec_node) {
index 0940553230596aed2ba41787b8605e26c2cc11c7..6f52eca05e2600f34c5b76deb77db81ab6fb9290 100644 (file)
@@ -138,7 +138,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
                .name = "rt5650_rt5676 Playback",
                .stream_name = "rt5650_rt5676 Playback",
                .cpu_dai_name = "DL1",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -149,7 +148,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
                .name = "rt5650_rt5676 Capture",
                .stream_name = "rt5650_rt5676 Capture",
                .cpu_dai_name = "VUL",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .codec_name = "snd-soc-dummy",
                .codec_dai_name = "snd-soc-dummy-dai",
                .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
@@ -161,7 +159,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
        {
                .name = "Codec",
                .cpu_dai_name = "I2S",
-               .platform_name = "11220000.mt8173-afe-pcm",
                .no_pcm = 1,
                .codecs = mt8173_rt5650_rt5676_codecs,
                .num_codecs = 2,
@@ -209,7 +206,21 @@ static struct snd_soc_card mt8173_rt5650_rt5676_card = {
 static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;
-       int ret;
+       struct device_node *platform_node;
+       int i, ret;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node,
+                                        "mediatek,platform", 0);
+       if (!platform_node) {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < card->num_links; i++) {
+               if (mt8173_rt5650_rt5676_dais[i].platform_name)
+                       continue;
+               mt8173_rt5650_rt5676_dais[i].platform_of_node = platform_node;
+       }
 
        mt8173_rt5650_rt5676_codecs[0].of_node =
                of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
index cc228db5fb760eaa24f98d91b0b14f0eded80ea9..9863da73dfe03a0f057d9897fd89e7d4d1614194 100644 (file)
@@ -1199,6 +1199,8 @@ err_pm_disable:
 static int mtk_afe_pcm_dev_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               mtk_afe_runtime_suspend(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
        return 0;
index 3a4a5c0e3f9737c795f74367b04c9825462651f8..0e1e69c7abd56b25fab6e4ffb0eab5fd574d03d2 100644 (file)
@@ -1716,6 +1716,7 @@ card_probe_error:
        if (card->remove)
                card->remove(card);
 
+       snd_soc_dapm_free(&card->dapm);
        soc_cleanup_card_debugfs(card);
        snd_card_free(card->snd_card);
 
index aa327c92480c56c2609699380594a75ad765fbda..e0de8072c5144e92fce3ec9518787a4db526d726 100644 (file)
@@ -358,9 +358,10 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
                        data->widget =
                                snd_soc_dapm_new_control_unlocked(widget->dapm,
                                &template);
+                       kfree(name);
                        if (!data->widget) {
                                ret = -ENOMEM;
-                               goto err_name;
+                               goto err_data;
                        }
                }
                break;
@@ -389,11 +390,12 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
                        data->value = template.on_val;
 
-                       data->widget = snd_soc_dapm_new_control(widget->dapm,
-                                       &template);
+                       data->widget = snd_soc_dapm_new_control_unlocked(
+                                               widget->dapm, &template);
+                       kfree(name);
                        if (!data->widget) {
                                ret = -ENOMEM;
-                               goto err_name;
+                               goto err_data;
                        }
 
                        snd_soc_dapm_add_path(widget->dapm, data->widget,
@@ -408,8 +410,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
        return 0;
 
-err_name:
-       kfree(name);
 err_data:
        kfree(data);
        return ret;
@@ -418,8 +418,6 @@ err_data:
 static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
-       if (data->widget)
-               kfree(data->widget->name);
        kfree(data->wlist);
        kfree(data);
 }
@@ -1952,6 +1950,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                           size_t count, loff_t *ppos)
 {
        struct snd_soc_dapm_widget *w = file->private_data;
+       struct snd_soc_card *card = w->dapm->card;
        char *buf;
        int in, out;
        ssize_t ret;
@@ -1961,6 +1960,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
        if (!buf)
                return -ENOMEM;
 
+       mutex_lock(&card->dapm_mutex);
+
        /* Supply widgets are not handled by is_connected_{input,output}_ep() */
        if (w->is_supply) {
                in = 0;
@@ -2007,6 +2008,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                                        p->sink->name);
        }
 
+       mutex_unlock(&card->dapm_mutex);
+
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
 
        kfree(buf);
@@ -2281,11 +2284,15 @@ static ssize_t dapm_widget_show(struct device *dev,
        struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
        int i, count = 0;
 
+       mutex_lock(&rtd->card->dapm_mutex);
+
        for (i = 0; i < rtd->num_codecs; i++) {
                struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
                count += dapm_widget_show_codec(codec, buf + count);
        }
 
+       mutex_unlock(&rtd->card->dapm_mutex);
+
        return count;
 }
 
@@ -3334,16 +3341,10 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
        }
 
        prefix = soc_dapm_prefix(dapm);
-       if (prefix) {
+       if (prefix)
                w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
-               if (widget->sname)
-                       w->sname = kasprintf(GFP_KERNEL, "%s %s", prefix,
-                                            widget->sname);
-       } else {
+       else
                w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
-               if (widget->sname)
-                       w->sname = kasprintf(GFP_KERNEL, "%s", widget->sname);
-       }
        if (w->name == NULL) {
                kfree(w);
                return NULL;
@@ -3792,7 +3793,7 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
                                break;
                        }
 
-                       if (!w->sname || !strstr(w->sname, dai_w->name))
+                       if (!w->sname || !strstr(w->sname, dai_w->sname))
                                continue;
 
                        if (dai_w->id == snd_soc_dapm_dai_in) {
index d0960683c4093c4303743b1e7e4f93190e11a3a5..31068b8f3db0dd965cc2bdc6742684dc2cb8d8ea 100644 (file)
@@ -33,6 +33,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/soc-topology.h>
+#include <sound/tlv.h>
 
 /*
  * We make several passes over the data (since it wont necessarily be ordered)
@@ -144,7 +145,7 @@ static const struct snd_soc_tplg_kcontrol_ops io_ops[] = {
        {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe,
                snd_soc_put_strobe, NULL},
        {SND_SOC_TPLG_DAPM_CTL_VOLSW, snd_soc_dapm_get_volsw,
-               snd_soc_dapm_put_volsw, NULL},
+               snd_soc_dapm_put_volsw, snd_soc_info_volsw},
        {SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE, snd_soc_dapm_get_enum_double,
                snd_soc_dapm_put_enum_double, snd_soc_info_enum_double},
        {SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT, snd_soc_dapm_get_enum_double,
@@ -534,7 +535,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
                        k->put = bops[i].put;
                if (k->get == NULL && bops[i].id == hdr->ops.get)
                        k->get = bops[i].get;
-               if (k->info == NULL && ops[i].id == hdr->ops.info)
+               if (k->info == NULL && bops[i].id == hdr->ops.info)
                        k->info = bops[i].info;
        }
 
@@ -579,29 +580,51 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
        return 0;
 }
 
+
+static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
+       struct snd_kcontrol_new *kc, struct snd_soc_tplg_tlv_dbscale *scale)
+{
+       unsigned int item_len = 2 * sizeof(unsigned int);
+       unsigned int *p;
+
+       p = kzalloc(item_len + 2 * sizeof(unsigned int), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       p[0] = SNDRV_CTL_TLVT_DB_SCALE;
+       p[1] = item_len;
+       p[2] = scale->min;
+       p[3] = (scale->step & TLV_DB_SCALE_MASK)
+                       | (scale->mute ? TLV_DB_SCALE_MUTE : 0);
+
+       kc->tlv.p = (void *)p;
+       return 0;
+}
+
 static int soc_tplg_create_tlv(struct soc_tplg *tplg,
-       struct snd_kcontrol_new *kc, u32 tlv_size)
+       struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
 {
        struct snd_soc_tplg_ctl_tlv *tplg_tlv;
-       struct snd_ctl_tlv *tlv;
 
-       if (tlv_size == 0)
+       if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
                return 0;
 
-       tplg_tlv = (struct snd_soc_tplg_ctl_tlv *) tplg->pos;
-       tplg->pos += tlv_size;
-
-       tlv = kzalloc(sizeof(*tlv) + tlv_size, GFP_KERNEL);
-       if (tlv == NULL)
-               return -ENOMEM;
-
-       dev_dbg(tplg->dev, " created TLV type %d size %d bytes\n",
-               tplg_tlv->numid, tplg_tlv->size);
+       if (tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+               kc->tlv.c = snd_soc_bytes_tlv_callback;
+       } else {
+               tplg_tlv = &tc->tlv;
+               switch (tplg_tlv->type) {
+               case SNDRV_CTL_TLVT_DB_SCALE:
+                       return soc_tplg_create_tlv_db_scale(tplg, kc,
+                                       &tplg_tlv->scale);
 
-       tlv->numid = tplg_tlv->numid;
-       tlv->length = tplg_tlv->size;
-       memcpy(tlv->tlv, tplg_tlv + 1, tplg_tlv->size);
-       kc->tlv.p = (void *)tlv;
+               /* TODO: add support for other TLV types */
+               default:
+                       dev_dbg(tplg->dev, "Unsupported TLV type %d\n",
+                                       tplg_tlv->type);
+                       return -EINVAL;
+               }
+       }
 
        return 0;
 }
@@ -773,7 +796,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
                }
 
                /* create any TLV data */
-               soc_tplg_create_tlv(tplg, &kc, mc->hdr.tlv_size);
+               soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
 
                /* register control here */
                err = soc_tplg_add_kcontrol(tplg, &kc,
@@ -1351,6 +1374,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
        template.reg = w->reg;
        template.shift = w->shift;
        template.mask = w->mask;
+       template.subseq = w->subseq;
        template.on_val = w->invert ? 0 : 1;
        template.off_val = w->invert ? 1 : 0;
        template.ignore_suspend = w->ignore_suspend;
index 98d96e1b17e05847aaa2b48740f3f9f0cc2c6e2a..1930c42e1f557ae62c30003b379088f242b0dbfe 100644 (file)
@@ -393,9 +393,9 @@ static int zx_i2s_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        zx_i2s->mapbase = res->start;
        zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (!zx_i2s->reg_base) {
+       if (IS_ERR(zx_i2s->reg_base)) {
                dev_err(&pdev->dev, "ioremap failed!\n");
-               return -EIO;
+               return PTR_ERR(zx_i2s->reg_base);
        }
 
        writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL);
index 11a0e46a1156913a23d9f31852fa508cbd1f8c5f..26265ce4caca17da4b6315a4627130ac63851063 100644 (file)
@@ -322,9 +322,9 @@ static int zx_spdif_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        zx_spdif->mapbase = res->start;
        zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (!zx_spdif->reg_base) {
+       if (IS_ERR(zx_spdif->reg_base)) {
                dev_err(&pdev->dev, "ioremap failed!\n");
-               return -EIO;
+               return PTR_ERR(zx_spdif->reg_base);
        }
 
        zx_spdif_dev_init(zx_spdif->reg_base);
index 1b1a89e80d1394bb253aecc3cadc683dbcff3a36..784ceb85b2d9fe7cbe989d0c8443863f1d03df34 100644 (file)
@@ -956,6 +956,7 @@ static int snd_amd7930_create(struct snd_card *card,
        if (!amd->regs) {
                snd_printk(KERN_ERR
                           "amd7930-%d: Unable to map chip registers.\n", dev);
+               kfree(amd);
                return -EIO;
        }
 
index 1fab9778807a0015f2578f0504306ed852eb4932..0450593980fd3525a65feca17dccea0e9940506e 100644 (file)
@@ -638,7 +638,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
        int err = -ENODEV;
 
        down_read(&chip->shutdown_rwsem);
-       if (chip->probing && chip->in_pm)
+       if (chip->probing || chip->in_pm)
                err = 0;
        else if (!chip->shutdown)
                err = usb_autopm_get_interface(chip->pm_intf);
index 8461d6bf992f8d39f709097be8305fc14efbb506..204cc074adb96f8f99ebd9d69bd7e1e4cf91f98e 100644 (file)
@@ -186,12 +186,8 @@ static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
        int ret = 0;
 
        spin_lock_irqsave(&pstr->lock, flags);
-       if (!test_and_set_bit(type, &pstr->running)) {
-               if (pstr->active_urbs || pstr->unlink_urbs) {
-                       ret = -EBUSY;
-                       goto error;
-               }
-
+       if (!test_and_set_bit(type, &pstr->running) &&
+           !(pstr->active_urbs || pstr->unlink_urbs)) {
                pstr->count = 0;
                /* Submit all currently available URBs */
                if (direction == SNDRV_PCM_STREAM_PLAYBACK)
@@ -199,7 +195,6 @@ static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
                else
                        ret = line6_submit_audio_in_all_urbs(line6pcm);
        }
- error:
        if (ret < 0)
                clear_bit(type, &pstr->running);
        spin_unlock_irqrestore(&pstr->lock, flags);
index e5000da9e9d7093f6e287194665de2d63f046e93..6a803eff87f71110049d9c39cb07025d2c64d828 100644 (file)
@@ -341,6 +341,20 @@ static const struct usbmix_name_map scms_usb3318_map[] = {
        { 0 }
 };
 
+/* Bose companion 5, the dB conversion factor is 16 instead of 256 */
+static struct usbmix_dB_map bose_companion5_dB = {-5006, -6};
+static struct usbmix_name_map bose_companion5_map[] = {
+       { 3, NULL, .dB = &bose_companion5_dB },
+       { 0 }   /* terminator */
+};
+
+/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */
+static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000};
+static struct usbmix_name_map dragonfly_1_2_map[] = {
+       { 7, NULL, .dB = &dragonfly_1_2_dB },
+       { 0 }   /* terminator */
+};
+
 /*
  * Control map entries
  */
@@ -451,6 +465,16 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x25c4, 0x0003),
                .map = scms_usb3318_map,
        },
+       {
+               /* Bose Companion 5 */
+               .id = USB_ID(0x05a7, 0x1020),
+               .map = bose_companion5_map,
+       },
+       {
+               /* Dragonfly DAC 1.2 */
+               .id = USB_ID(0x21b4, 0x0081),
+               .map = dragonfly_1_2_map,
+       },
        { 0 } /* terminator */
 };
 
index 2f6d3e9a1bcd0144cf81d77f3ec085af3984d07e..e4756651a52c8873457ae340450934dcfbd5dfad 100644 (file)
@@ -2512,6 +2512,74 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* Steinberg devices */
+{
+       /* Steinberg MI2 */
+       USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x2040),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = & (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = &(const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /* Steinberg MI4 */
+       USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x4040),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = & (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = &(const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
 /* TerraTec devices */
 {
        USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
index f0e72674c52d2c9b88b46cb281db39fe8fb68d8d..9098083869c85a62bc4df5bcf8df96f5ffcc7e00 100644 (file)
 
 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
 
+#include <linux/types.h>
+
+static __always_inline void __read_once_size(const volatile void *p, void *res, int size)
+{
+       switch (size) {
+       case 1: *(__u8 *)res = *(volatile __u8 *)p; break;
+       case 2: *(__u16 *)res = *(volatile __u16 *)p; break;
+       case 4: *(__u32 *)res = *(volatile __u32 *)p; break;
+       case 8: *(__u64 *)res = *(volatile __u64 *)p; break;
+       default:
+               barrier();
+               __builtin_memcpy((void *)res, (const void *)p, size);
+               barrier();
+       }
+}
+
+static __always_inline void __write_once_size(volatile void *p, void *res, int size)
+{
+       switch (size) {
+       case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
+       case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
+       case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
+       case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
+       default:
+               barrier();
+               __builtin_memcpy((void *)p, (const void *)res, size);
+               barrier();
+       }
+}
+
+/*
+ * Prevent the compiler from merging or refetching reads or writes. The
+ * compiler is also forbidden from reordering successive instances of
+ * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the
+ * compiler is aware of some particular ordering.  One way to make the
+ * compiler aware of ordering is to put the two invocations of READ_ONCE,
+ * WRITE_ONCE or ACCESS_ONCE() in different C statements.
+ *
+ * In contrast to ACCESS_ONCE these two macros will also work on aggregate
+ * data types like structs or unions. If the size of the accessed data
+ * type exceeds the word size of the machine (e.g., 32 bits or 64 bits)
+ * READ_ONCE() and WRITE_ONCE()  will fall back to memcpy and print a
+ * compile-time warning.
+ *
+ * Their two major use cases are: (1) Mediating communication between
+ * process-level code and irq/NMI handlers, all running on the same CPU,
+ * and (2) Ensuring that the compiler does not  fold, spindle, or otherwise
+ * mutilate accesses that either do not require ordering or that interact
+ * with an explicit memory barrier or atomic instruction that provides the
+ * required ordering.
+ */
+
+#define READ_ONCE(x) \
+       ({ union { typeof(x) __val; char __c[1]; } __u; __read_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
+
+#define WRITE_ONCE(x, val) \
+       ({ union { typeof(x) __val; char __c[1]; } __u = { .__val = (val) }; __write_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
+
 #endif /* _TOOLS_LINUX_COMPILER_H */
diff --git a/tools/include/linux/export.h b/tools/include/linux/export.h
deleted file mode 100644 (file)
index d07e586..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _TOOLS_LINUX_EXPORT_H_
-#define _TOOLS_LINUX_EXPORT_H_
-
-#define EXPORT_SYMBOL(sym)
-#define EXPORT_SYMBOL_GPL(sym)
-#define EXPORT_SYMBOL_GPL_FUTURE(sym)
-#define EXPORT_UNUSED_SYMBOL(sym)
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)
-
-#endif
diff --git a/tools/include/linux/rbtree.h b/tools/include/linux/rbtree.h
new file mode 100644 (file)
index 0000000..1125822
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+
+  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
+
+  linux/include/linux/rbtree.h
+
+  To use rbtrees you'll have to implement your own insert and search cores.
+  This will avoid us to use callbacks and to drop drammatically performances.
+  I know it's not the cleaner way,  but in C (not in C++) to get
+  performances and genericity...
+
+  See Documentation/rbtree.txt for documentation and samples.
+*/
+
+#ifndef __TOOLS_LINUX_PERF_RBTREE_H
+#define __TOOLS_LINUX_PERF_RBTREE_H
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+
+struct rb_node {
+       unsigned long  __rb_parent_color;
+       struct rb_node *rb_right;
+       struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+    /* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root {
+       struct rb_node *rb_node;
+};
+
+
+#define rb_parent(r)   ((struct rb_node *)((r)->__rb_parent_color & ~3))
+
+#define RB_ROOT        (struct rb_root) { NULL, }
+#define        rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root)  ((root)->rb_node == NULL)
+
+/* 'empty' nodes are nodes that are known not to be inserted in an rbtree */
+#define RB_EMPTY_NODE(node)  \
+       ((node)->__rb_parent_color == (unsigned long)(node))
+#define RB_CLEAR_NODE(node)  \
+       ((node)->__rb_parent_color = (unsigned long)(node))
+
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(const struct rb_node *);
+extern struct rb_node *rb_prev(const struct rb_node *);
+extern struct rb_node *rb_first(const struct rb_root *);
+extern struct rb_node *rb_last(const struct rb_root *);
+
+/* Postorder iteration - always visit the parent after its children */
+extern struct rb_node *rb_first_postorder(const struct rb_root *);
+extern struct rb_node *rb_next_postorder(const struct rb_node *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+                           struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node *node, struct rb_node *parent,
+                               struct rb_node **rb_link)
+{
+       node->__rb_parent_color = (unsigned long)parent;
+       node->rb_left = node->rb_right = NULL;
+
+       *rb_link = node;
+}
+
+#define rb_entry_safe(ptr, type, member) \
+       ({ typeof(ptr) ____ptr = (ptr); \
+          ____ptr ? rb_entry(____ptr, type, member) : NULL; \
+       })
+
+
+/*
+ * Handy for checking that we are not deleting an entry that is
+ * already in a list, found in block/{blk-throttle,cfq-iosched}.c,
+ * probably should be moved to lib/rbtree.c...
+ */
+static inline void rb_erase_init(struct rb_node *n, struct rb_root *root)
+{
+       rb_erase(n, root);
+       RB_CLEAR_NODE(n);
+}
+#endif /* __TOOLS_LINUX_PERF_RBTREE_H */
diff --git a/tools/include/linux/rbtree_augmented.h b/tools/include/linux/rbtree_augmented.h
new file mode 100644 (file)
index 0000000..43be941
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  (C) 2002  David Woodhouse <dwmw2@infradead.org>
+  (C) 2012  Michel Lespinasse <walken@google.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  tools/linux/include/linux/rbtree_augmented.h
+
+  Copied from:
+  linux/include/linux/rbtree_augmented.h
+*/
+
+#ifndef _TOOLS_LINUX_RBTREE_AUGMENTED_H
+#define _TOOLS_LINUX_RBTREE_AUGMENTED_H
+
+#include <linux/compiler.h>
+#include <linux/rbtree.h>
+
+/*
+ * Please note - only struct rb_augment_callbacks and the prototypes for
+ * rb_insert_augmented() and rb_erase_augmented() are intended to be public.
+ * The rest are implementation details you are not expected to depend on.
+ *
+ * See Documentation/rbtree.txt for documentation and samples.
+ */
+
+struct rb_augment_callbacks {
+       void (*propagate)(struct rb_node *node, struct rb_node *stop);
+       void (*copy)(struct rb_node *old, struct rb_node *new);
+       void (*rotate)(struct rb_node *old, struct rb_node *new);
+};
+
+extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+       void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
+/*
+ * Fixup the rbtree and update the augmented information when rebalancing.
+ *
+ * On insertion, the user must update the augmented information on the path
+ * leading to the inserted node, then call rb_link_node() as usual and
+ * rb_augment_inserted() instead of the usual rb_insert_color() call.
+ * If rb_augment_inserted() rebalances the rbtree, it will callback into
+ * a user provided function to update the augmented information on the
+ * affected subtrees.
+ */
+static inline void
+rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+                   const struct rb_augment_callbacks *augment)
+{
+       __rb_insert_augmented(node, root, augment->rotate);
+}
+
+#define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield,      \
+                            rbtype, rbaugmented, rbcompute)            \
+static inline void                                                     \
+rbname ## _propagate(struct rb_node *rb, struct rb_node *stop)         \
+{                                                                      \
+       while (rb != stop) {                                            \
+               rbstruct *node = rb_entry(rb, rbstruct, rbfield);       \
+               rbtype augmented = rbcompute(node);                     \
+               if (node->rbaugmented == augmented)                     \
+                       break;                                          \
+               node->rbaugmented = augmented;                          \
+               rb = rb_parent(&node->rbfield);                         \
+       }                                                               \
+}                                                                      \
+static inline void                                                     \
+rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new)                \
+{                                                                      \
+       rbstruct *old = rb_entry(rb_old, rbstruct, rbfield);            \
+       rbstruct *new = rb_entry(rb_new, rbstruct, rbfield);            \
+       new->rbaugmented = old->rbaugmented;                            \
+}                                                                      \
+static void                                                            \
+rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new)      \
+{                                                                      \
+       rbstruct *old = rb_entry(rb_old, rbstruct, rbfield);            \
+       rbstruct *new = rb_entry(rb_new, rbstruct, rbfield);            \
+       new->rbaugmented = old->rbaugmented;                            \
+       old->rbaugmented = rbcompute(old);                              \
+}                                                                      \
+rbstatic const struct rb_augment_callbacks rbname = {                  \
+       rbname ## _propagate, rbname ## _copy, rbname ## _rotate        \
+};
+
+
+#define        RB_RED          0
+#define        RB_BLACK        1
+
+#define __rb_parent(pc)    ((struct rb_node *)(pc & ~3))
+
+#define __rb_color(pc)     ((pc) & 1)
+#define __rb_is_black(pc)  __rb_color(pc)
+#define __rb_is_red(pc)    (!__rb_color(pc))
+#define rb_color(rb)       __rb_color((rb)->__rb_parent_color)
+#define rb_is_red(rb)      __rb_is_red((rb)->__rb_parent_color)
+#define rb_is_black(rb)    __rb_is_black((rb)->__rb_parent_color)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+       rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
+}
+
+static inline void rb_set_parent_color(struct rb_node *rb,
+                                      struct rb_node *p, int color)
+{
+       rb->__rb_parent_color = (unsigned long)p | color;
+}
+
+static inline void
+__rb_change_child(struct rb_node *old, struct rb_node *new,
+                 struct rb_node *parent, struct rb_root *root)
+{
+       if (parent) {
+               if (parent->rb_left == old)
+                       parent->rb_left = new;
+               else
+                       parent->rb_right = new;
+       } else
+               root->rb_node = new;
+}
+
+extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
+       void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
+
+static __always_inline struct rb_node *
+__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+                    const struct rb_augment_callbacks *augment)
+{
+       struct rb_node *child = node->rb_right, *tmp = node->rb_left;
+       struct rb_node *parent, *rebalance;
+       unsigned long pc;
+
+       if (!tmp) {
+               /*
+                * Case 1: node to erase has no more than 1 child (easy!)
+                *
+                * Note that if there is one child it must be red due to 5)
+                * and node must be black due to 4). We adjust colors locally
+                * so as to bypass __rb_erase_color() later on.
+                */
+               pc = node->__rb_parent_color;
+               parent = __rb_parent(pc);
+               __rb_change_child(node, child, parent, root);
+               if (child) {
+                       child->__rb_parent_color = pc;
+                       rebalance = NULL;
+               } else
+                       rebalance = __rb_is_black(pc) ? parent : NULL;
+               tmp = parent;
+       } else if (!child) {
+               /* Still case 1, but this time the child is node->rb_left */
+               tmp->__rb_parent_color = pc = node->__rb_parent_color;
+               parent = __rb_parent(pc);
+               __rb_change_child(node, tmp, parent, root);
+               rebalance = NULL;
+               tmp = parent;
+       } else {
+               struct rb_node *successor = child, *child2;
+               tmp = child->rb_left;
+               if (!tmp) {
+                       /*
+                        * Case 2: node's successor is its right child
+                        *
+                        *    (n)          (s)
+                        *    / \          / \
+                        *  (x) (s)  ->  (x) (c)
+                        *        \
+                        *        (c)
+                        */
+                       parent = successor;
+                       child2 = successor->rb_right;
+                       augment->copy(node, successor);
+               } else {
+                       /*
+                        * Case 3: node's successor is leftmost under
+                        * node's right child subtree
+                        *
+                        *    (n)          (s)
+                        *    / \          / \
+                        *  (x) (y)  ->  (x) (y)
+                        *      /            /
+                        *    (p)          (p)
+                        *    /            /
+                        *  (s)          (c)
+                        *    \
+                        *    (c)
+                        */
+                       do {
+                               parent = successor;
+                               successor = tmp;
+                               tmp = tmp->rb_left;
+                       } while (tmp);
+                       parent->rb_left = child2 = successor->rb_right;
+                       successor->rb_right = child;
+                       rb_set_parent(child, successor);
+                       augment->copy(node, successor);
+                       augment->propagate(parent, successor);
+               }
+
+               successor->rb_left = tmp = node->rb_left;
+               rb_set_parent(tmp, successor);
+
+               pc = node->__rb_parent_color;
+               tmp = __rb_parent(pc);
+               __rb_change_child(node, successor, tmp, root);
+               if (child2) {
+                       successor->__rb_parent_color = pc;
+                       rb_set_parent_color(child2, parent, RB_BLACK);
+                       rebalance = NULL;
+               } else {
+                       unsigned long pc2 = successor->__rb_parent_color;
+                       successor->__rb_parent_color = pc;
+                       rebalance = __rb_is_black(pc2) ? parent : NULL;
+               }
+               tmp = successor;
+       }
+
+       augment->propagate(tmp, NULL);
+       return rebalance;
+}
+
+static __always_inline void
+rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+                  const struct rb_augment_callbacks *augment)
+{
+       struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
+       if (rebalance)
+               __rb_erase_color(rebalance, root, augment->rotate);
+}
+
+#endif /* _TOOLS_LINUX_RBTREE_AUGMENTED_H */
index 8bd9606584632582f7e893c0a3c01e8f0240678f..fe1b02c2c95bbe1274376f1b20ffebfac7358cc7 100644 (file)
@@ -36,7 +36,7 @@ $(LIBFILE): $(API_IN)
 
 clean:
        $(call QUIET_CLEAN, libapi) $(RM) $(LIBFILE); \
-       find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o | xargs $(RM)
+       find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
 
 FORCE:
 
diff --git a/tools/lib/hweight.c b/tools/lib/hweight.c
new file mode 100644 (file)
index 0000000..0b859b8
--- /dev/null
@@ -0,0 +1,62 @@
+#include <linux/bitops.h>
+#include <asm/types.h>
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+unsigned int __sw_hweight32(unsigned int w)
+{
+#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER
+       w -= (w >> 1) & 0x55555555;
+       w =  (w & 0x33333333) + ((w >> 2) & 0x33333333);
+       w =  (w + (w >> 4)) & 0x0f0f0f0f;
+       return (w * 0x01010101) >> 24;
+#else
+       unsigned int res = w - ((w >> 1) & 0x55555555);
+       res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+       res = (res + (res >> 4)) & 0x0F0F0F0F;
+       res = res + (res >> 8);
+       return (res + (res >> 16)) & 0x000000FF;
+#endif
+}
+
+unsigned int __sw_hweight16(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x5555);
+       res = (res & 0x3333) + ((res >> 2) & 0x3333);
+       res = (res + (res >> 4)) & 0x0F0F;
+       return (res + (res >> 8)) & 0x00FF;
+}
+
+unsigned int __sw_hweight8(unsigned int w)
+{
+       unsigned int res = w - ((w >> 1) & 0x55);
+       res = (res & 0x33) + ((res >> 2) & 0x33);
+       return (res + (res >> 4)) & 0x0F;
+}
+
+unsigned long __sw_hweight64(__u64 w)
+{
+#if BITS_PER_LONG == 32
+       return __sw_hweight32((unsigned int)(w >> 32)) +
+              __sw_hweight32((unsigned int)w);
+#elif BITS_PER_LONG == 64
+#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER
+       w -= (w >> 1) & 0x5555555555555555ul;
+       w =  (w & 0x3333333333333333ul) + ((w >> 2) & 0x3333333333333333ul);
+       w =  (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0ful;
+       return (w * 0x0101010101010101ul) >> 56;
+#else
+       __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
+       res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
+       res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
+       res = res + (res >> 8);
+       res = res + (res >> 16);
+       return (res + (res >> 32)) & 0x00000000000000FFul;
+#endif
+#endif
+}
diff --git a/tools/lib/rbtree.c b/tools/lib/rbtree.c
new file mode 100644 (file)
index 0000000..17c2b59
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea@suse.de>
+  (C) 2002  David Woodhouse <dwmw2@infradead.org>
+  (C) 2012  Michel Lespinasse <walken@google.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  linux/lib/rbtree.c
+*/
+
+#include <linux/rbtree_augmented.h>
+
+/*
+ * red-black trees properties:  http://en.wikipedia.org/wiki/Rbtree
+ *
+ *  1) A node is either red or black
+ *  2) The root is black
+ *  3) All leaves (NULL) are black
+ *  4) Both children of every red node are black
+ *  5) Every simple path from root to leaves contains the same number
+ *     of black nodes.
+ *
+ *  4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two
+ *  consecutive red nodes in a path and every red node is therefore followed by
+ *  a black. So if B is the number of black nodes on every simple path (as per
+ *  5), then the longest possible path due to 4 is 2B.
+ *
+ *  We shall indicate color with case, where black nodes are uppercase and red
+ *  nodes will be lowercase. Unknown color nodes shall be drawn as red within
+ *  parentheses and have some accompanying text comment.
+ */
+
+static inline void rb_set_black(struct rb_node *rb)
+{
+       rb->__rb_parent_color |= RB_BLACK;
+}
+
+static inline struct rb_node *rb_red_parent(struct rb_node *red)
+{
+       return (struct rb_node *)red->__rb_parent_color;
+}
+
+/*
+ * Helper function for rotations:
+ * - old's parent and color get assigned to new
+ * - old gets assigned new as a parent and 'color' as a color.
+ */
+static inline void
+__rb_rotate_set_parents(struct rb_node *old, struct rb_node *new,
+                       struct rb_root *root, int color)
+{
+       struct rb_node *parent = rb_parent(old);
+       new->__rb_parent_color = old->__rb_parent_color;
+       rb_set_parent_color(old, new, color);
+       __rb_change_child(old, new, parent, root);
+}
+
+static __always_inline void
+__rb_insert(struct rb_node *node, struct rb_root *root,
+           void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
+{
+       struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
+
+       while (true) {
+               /*
+                * Loop invariant: node is red
+                *
+                * If there is a black parent, we are done.
+                * Otherwise, take some corrective action as we don't
+                * want a red root or two consecutive red nodes.
+                */
+               if (!parent) {
+                       rb_set_parent_color(node, NULL, RB_BLACK);
+                       break;
+               } else if (rb_is_black(parent))
+                       break;
+
+               gparent = rb_red_parent(parent);
+
+               tmp = gparent->rb_right;
+               if (parent != tmp) {    /* parent == gparent->rb_left */
+                       if (tmp && rb_is_red(tmp)) {
+                               /*
+                                * Case 1 - color flips
+                                *
+                                *       G            g
+                                *      / \          / \
+                                *     p   u  -->   P   U
+                                *    /            /
+                                *   n            n
+                                *
+                                * However, since g's parent might be red, and
+                                * 4) does not allow this, we need to recurse
+                                * at g.
+                                */
+                               rb_set_parent_color(tmp, gparent, RB_BLACK);
+                               rb_set_parent_color(parent, gparent, RB_BLACK);
+                               node = gparent;
+                               parent = rb_parent(node);
+                               rb_set_parent_color(node, parent, RB_RED);
+                               continue;
+                       }
+
+                       tmp = parent->rb_right;
+                       if (node == tmp) {
+                               /*
+                                * Case 2 - left rotate at parent
+                                *
+                                *      G             G
+                                *     / \           / \
+                                *    p   U  -->    n   U
+                                *     \           /
+                                *      n         p
+                                *
+                                * This still leaves us in violation of 4), the
+                                * continuation into Case 3 will fix that.
+                                */
+                               parent->rb_right = tmp = node->rb_left;
+                               node->rb_left = parent;
+                               if (tmp)
+                                       rb_set_parent_color(tmp, parent,
+                                                           RB_BLACK);
+                               rb_set_parent_color(parent, node, RB_RED);
+                               augment_rotate(parent, node);
+                               parent = node;
+                               tmp = node->rb_right;
+                       }
+
+                       /*
+                        * Case 3 - right rotate at gparent
+                        *
+                        *        G           P
+                        *       / \         / \
+                        *      p   U  -->  n   g
+                        *     /                 \
+                        *    n                   U
+                        */
+                       gparent->rb_left = tmp;  /* == parent->rb_right */
+                       parent->rb_right = gparent;
+                       if (tmp)
+                               rb_set_parent_color(tmp, gparent, RB_BLACK);
+                       __rb_rotate_set_parents(gparent, parent, root, RB_RED);
+                       augment_rotate(gparent, parent);
+                       break;
+               } else {
+                       tmp = gparent->rb_left;
+                       if (tmp && rb_is_red(tmp)) {
+                               /* Case 1 - color flips */
+                               rb_set_parent_color(tmp, gparent, RB_BLACK);
+                               rb_set_parent_color(parent, gparent, RB_BLACK);
+                               node = gparent;
+                               parent = rb_parent(node);
+                               rb_set_parent_color(node, parent, RB_RED);
+                               continue;
+                       }
+
+                       tmp = parent->rb_left;
+                       if (node == tmp) {
+                               /* Case 2 - right rotate at parent */
+                               parent->rb_left = tmp = node->rb_right;
+                               node->rb_right = parent;
+                               if (tmp)
+                                       rb_set_parent_color(tmp, parent,
+                                                           RB_BLACK);
+                               rb_set_parent_color(parent, node, RB_RED);
+                               augment_rotate(parent, node);
+                               parent = node;
+                               tmp = node->rb_left;
+                       }
+
+                       /* Case 3 - left rotate at gparent */
+                       gparent->rb_right = tmp;  /* == parent->rb_left */
+                       parent->rb_left = gparent;
+                       if (tmp)
+                               rb_set_parent_color(tmp, gparent, RB_BLACK);
+                       __rb_rotate_set_parents(gparent, parent, root, RB_RED);
+                       augment_rotate(gparent, parent);
+                       break;
+               }
+       }
+}
+
+/*
+ * Inline version for rb_erase() use - we want to be able to inline
+ * and eliminate the dummy_rotate callback there
+ */
+static __always_inline void
+____rb_erase_color(struct rb_node *parent, struct rb_root *root,
+       void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
+{
+       struct rb_node *node = NULL, *sibling, *tmp1, *tmp2;
+
+       while (true) {
+               /*
+                * Loop invariants:
+                * - node is black (or NULL on first iteration)
+                * - node is not the root (parent is not NULL)
+                * - All leaf paths going through parent and node have a
+                *   black node count that is 1 lower than other leaf paths.
+                */
+               sibling = parent->rb_right;
+               if (node != sibling) {  /* node == parent->rb_left */
+                       if (rb_is_red(sibling)) {
+                               /*
+                                * Case 1 - left rotate at parent
+                                *
+                                *     P               S
+                                *    / \             / \
+                                *   N   s    -->    p   Sr
+                                *      / \         / \
+                                *     Sl  Sr      N   Sl
+                                */
+                               parent->rb_right = tmp1 = sibling->rb_left;
+                               sibling->rb_left = parent;
+                               rb_set_parent_color(tmp1, parent, RB_BLACK);
+                               __rb_rotate_set_parents(parent, sibling, root,
+                                                       RB_RED);
+                               augment_rotate(parent, sibling);
+                               sibling = tmp1;
+                       }
+                       tmp1 = sibling->rb_right;
+                       if (!tmp1 || rb_is_black(tmp1)) {
+                               tmp2 = sibling->rb_left;
+                               if (!tmp2 || rb_is_black(tmp2)) {
+                                       /*
+                                        * Case 2 - sibling color flip
+                                        * (p could be either color here)
+                                        *
+                                        *    (p)           (p)
+                                        *    / \           / \
+                                        *   N   S    -->  N   s
+                                        *      / \           / \
+                                        *     Sl  Sr        Sl  Sr
+                                        *
+                                        * This leaves us violating 5) which
+                                        * can be fixed by flipping p to black
+                                        * if it was red, or by recursing at p.
+                                        * p is red when coming from Case 1.
+                                        */
+                                       rb_set_parent_color(sibling, parent,
+                                                           RB_RED);
+                                       if (rb_is_red(parent))
+                                               rb_set_black(parent);
+                                       else {
+                                               node = parent;
+                                               parent = rb_parent(node);
+                                               if (parent)
+                                                       continue;
+                                       }
+                                       break;
+                               }
+                               /*
+                                * Case 3 - right rotate at sibling
+                                * (p could be either color here)
+                                *
+                                *   (p)           (p)
+                                *   / \           / \
+                                *  N   S    -->  N   Sl
+                                *     / \             \
+                                *    sl  Sr            s
+                                *                       \
+                                *                        Sr
+                                */
+                               sibling->rb_left = tmp1 = tmp2->rb_right;
+                               tmp2->rb_right = sibling;
+                               parent->rb_right = tmp2;
+                               if (tmp1)
+                                       rb_set_parent_color(tmp1, sibling,
+                                                           RB_BLACK);
+                               augment_rotate(sibling, tmp2);
+                               tmp1 = sibling;
+                               sibling = tmp2;
+                       }
+                       /*
+                        * Case 4 - left rotate at parent + color flips
+                        * (p and sl could be either color here.
+                        *  After rotation, p becomes black, s acquires
+                        *  p's color, and sl keeps its color)
+                        *
+                        *      (p)             (s)
+                        *      / \             / \
+                        *     N   S     -->   P   Sr
+                        *        / \         / \
+                        *      (sl) sr      N  (sl)
+                        */
+                       parent->rb_right = tmp2 = sibling->rb_left;
+                       sibling->rb_left = parent;
+                       rb_set_parent_color(tmp1, sibling, RB_BLACK);
+                       if (tmp2)
+                               rb_set_parent(tmp2, parent);
+                       __rb_rotate_set_parents(parent, sibling, root,
+                                               RB_BLACK);
+                       augment_rotate(parent, sibling);
+                       break;
+               } else {
+                       sibling = parent->rb_left;
+                       if (rb_is_red(sibling)) {
+                               /* Case 1 - right rotate at parent */
+                               parent->rb_left = tmp1 = sibling->rb_right;
+                               sibling->rb_right = parent;
+                               rb_set_parent_color(tmp1, parent, RB_BLACK);
+                               __rb_rotate_set_parents(parent, sibling, root,
+                                                       RB_RED);
+                               augment_rotate(parent, sibling);
+                               sibling = tmp1;
+                       }
+                       tmp1 = sibling->rb_left;
+                       if (!tmp1 || rb_is_black(tmp1)) {
+                               tmp2 = sibling->rb_right;
+                               if (!tmp2 || rb_is_black(tmp2)) {
+                                       /* Case 2 - sibling color flip */
+                                       rb_set_parent_color(sibling, parent,
+                                                           RB_RED);
+                                       if (rb_is_red(parent))
+                                               rb_set_black(parent);
+                                       else {
+                                               node = parent;
+                                               parent = rb_parent(node);
+                                               if (parent)
+                                                       continue;
+                                       }
+                                       break;
+                               }
+                               /* Case 3 - right rotate at sibling */
+                               sibling->rb_right = tmp1 = tmp2->rb_left;
+                               tmp2->rb_left = sibling;
+                               parent->rb_left = tmp2;
+                               if (tmp1)
+                                       rb_set_parent_color(tmp1, sibling,
+                                                           RB_BLACK);
+                               augment_rotate(sibling, tmp2);
+                               tmp1 = sibling;
+                               sibling = tmp2;
+                       }
+                       /* Case 4 - left rotate at parent + color flips */
+                       parent->rb_left = tmp2 = sibling->rb_right;
+                       sibling->rb_right = parent;
+                       rb_set_parent_color(tmp1, sibling, RB_BLACK);
+                       if (tmp2)
+                               rb_set_parent(tmp2, parent);
+                       __rb_rotate_set_parents(parent, sibling, root,
+                                               RB_BLACK);
+                       augment_rotate(parent, sibling);
+                       break;
+               }
+       }
+}
+
+/* Non-inline version for rb_erase_augmented() use */
+void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
+       void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
+{
+       ____rb_erase_color(parent, root, augment_rotate);
+}
+
+/*
+ * Non-augmented rbtree manipulation functions.
+ *
+ * We use dummy augmented callbacks here, and have the compiler optimize them
+ * out of the rb_insert_color() and rb_erase() function definitions.
+ */
+
+static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {}
+static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {}
+static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {}
+
+static const struct rb_augment_callbacks dummy_callbacks = {
+       dummy_propagate, dummy_copy, dummy_rotate
+};
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+       __rb_insert(node, root, dummy_rotate);
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+       struct rb_node *rebalance;
+       rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
+       if (rebalance)
+               ____rb_erase_color(rebalance, root, dummy_rotate);
+}
+
+/*
+ * Augmented rbtree manipulation functions.
+ *
+ * This instantiates the same __always_inline functions as in the non-augmented
+ * case, but this time with user-defined callbacks.
+ */
+
+void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
+       void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
+{
+       __rb_insert(node, root, augment_rotate);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(const struct rb_root *root)
+{
+       struct rb_node  *n;
+
+       n = root->rb_node;
+       if (!n)
+               return NULL;
+       while (n->rb_left)
+               n = n->rb_left;
+       return n;
+}
+
+struct rb_node *rb_last(const struct rb_root *root)
+{
+       struct rb_node  *n;
+
+       n = root->rb_node;
+       if (!n)
+               return NULL;
+       while (n->rb_right)
+               n = n->rb_right;
+       return n;
+}
+
+struct rb_node *rb_next(const struct rb_node *node)
+{
+       struct rb_node *parent;
+
+       if (RB_EMPTY_NODE(node))
+               return NULL;
+
+       /*
+        * If we have a right-hand child, go down and then left as far
+        * as we can.
+        */
+       if (node->rb_right) {
+               node = node->rb_right;
+               while (node->rb_left)
+                       node=node->rb_left;
+               return (struct rb_node *)node;
+       }
+
+       /*
+        * No right-hand children. Everything down and left is smaller than us,
+        * so any 'next' node must be in the general direction of our parent.
+        * Go up the tree; any time the ancestor is a right-hand child of its
+        * parent, keep going up. First time it's a left-hand child of its
+        * parent, said parent is our 'next' node.
+        */
+       while ((parent = rb_parent(node)) && node == parent->rb_right)
+               node = parent;
+
+       return parent;
+}
+
+struct rb_node *rb_prev(const struct rb_node *node)
+{
+       struct rb_node *parent;
+
+       if (RB_EMPTY_NODE(node))
+               return NULL;
+
+       /*
+        * If we have a left-hand child, go down and then right as far
+        * as we can.
+        */
+       if (node->rb_left) {
+               node = node->rb_left;
+               while (node->rb_right)
+                       node=node->rb_right;
+               return (struct rb_node *)node;
+       }
+
+       /*
+        * No left-hand children. Go up till we find an ancestor which
+        * is a right-hand child of its parent.
+        */
+       while ((parent = rb_parent(node)) && node == parent->rb_left)
+               node = parent;
+
+       return parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+                    struct rb_root *root)
+{
+       struct rb_node *parent = rb_parent(victim);
+
+       /* Set the surrounding nodes to point to the replacement */
+       __rb_change_child(victim, new, parent, root);
+       if (victim->rb_left)
+               rb_set_parent(victim->rb_left, new);
+       if (victim->rb_right)
+               rb_set_parent(victim->rb_right, new);
+
+       /* Copy the pointers/colour from the victim to the replacement */
+       *new = *victim;
+}
+
+static struct rb_node *rb_left_deepest_node(const struct rb_node *node)
+{
+       for (;;) {
+               if (node->rb_left)
+                       node = node->rb_left;
+               else if (node->rb_right)
+                       node = node->rb_right;
+               else
+                       return (struct rb_node *)node;
+       }
+}
+
+struct rb_node *rb_next_postorder(const struct rb_node *node)
+{
+       const struct rb_node *parent;
+       if (!node)
+               return NULL;
+       parent = rb_parent(node);
+
+       /* If we're sitting on node, we've already seen our children */
+       if (parent && node == parent->rb_left && parent->rb_right) {
+               /* If we are the parent's left node, go to the parent's right
+                * node then all the way down to the left */
+               return rb_left_deepest_node(parent->rb_right);
+       } else
+               /* Otherwise we are the parent's right node, and the parent
+                * should be next */
+               return (struct rb_node *)parent;
+}
+
+struct rb_node *rb_first_postorder(const struct rb_root *root)
+{
+       if (!root->rb_node)
+               return NULL;
+
+       return rb_left_deepest_node(root->rb_node);
+}
index 6daaff652affdde16240c91330781864aaedfd35..7851df1490e0a81f6a17776bbdb464f564a99894 100644 (file)
@@ -268,7 +268,7 @@ install: install_lib
 
 clean:
        $(call QUIET_CLEAN, libtraceevent) \
-               $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
+               $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd \
                $(RM) TRACEEVENT-CFLAGS tags TAGS
 
 PHONY += force plugins
index fe50a1b34aa0035dec38a07a752ae33df9ad0e5d..d01a0aad5a01b7e2e5c8d0f45d90c72f9e713574 100644 (file)
@@ -18,6 +18,8 @@ tools/arch/x86/include/asm/atomic.h
 tools/arch/x86/include/asm/rmwcc.h
 tools/lib/traceevent
 tools/lib/api
+tools/lib/hweight.c
+tools/lib/rbtree.c
 tools/lib/symbol/kallsyms.c
 tools/lib/symbol/kallsyms.h
 tools/lib/util/find_next_bit.c
@@ -44,6 +46,8 @@ tools/include/linux/kernel.h
 tools/include/linux/list.h
 tools/include/linux/log2.h
 tools/include/linux/poison.h
+tools/include/linux/rbtree.h
+tools/include/linux/rbtree_augmented.h
 tools/include/linux/types.h
 include/asm-generic/bitops/arch_hweight.h
 include/asm-generic/bitops/const_hweight.h
@@ -51,12 +55,9 @@ include/asm-generic/bitops/fls64.h
 include/asm-generic/bitops/__fls.h
 include/asm-generic/bitops/fls.h
 include/linux/perf_event.h
-include/linux/rbtree.h
 include/linux/list.h
 include/linux/hash.h
 include/linux/stringify.h
-lib/hweight.c
-lib/rbtree.c
 include/linux/swab.h
 arch/*/include/asm/unistd*.h
 arch/*/include/uapi/asm/unistd*.h
@@ -65,7 +66,6 @@ arch/*/lib/memcpy*.S
 arch/*/lib/memset*.S
 include/linux/poison.h
 include/linux/hw_breakpoint.h
-include/linux/rbtree_augmented.h
 include/uapi/linux/perf_event.h
 include/uapi/linux/const.h
 include/uapi/linux/swab.h
index 7a4b549214e34715aaf2ff7b834598ef2bae8080..bba34636b7334b334bdb520d3ebd8925f86f84c0 100644 (file)
@@ -109,9 +109,22 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
        $(Q)$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
        $(Q)touch $(OUTPUT)PERF-VERSION-FILE
 
-CC = $(CROSS_COMPILE)gcc
-LD ?= $(CROSS_COMPILE)ld
-AR = $(CROSS_COMPILE)ar
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,LD,$(CROSS_COMPILE)ld)
+
 PKG_CONFIG = $(CROSS_COMPILE)pkg-config
 
 RM      = rm -f
index de165a1b92402ac7a6267bd0a0c5aa30a0053c92..20b56eb987f89f21fe20e53decf8ee1fbe275a2e 100644 (file)
@@ -521,6 +521,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                goto out_child;
        }
 
+       /*
+        * Normally perf_session__new would do this, but it doesn't have the
+        * evlist.
+        */
+       if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
+               pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
+               rec->tool.ordered_events = false;
+       }
+
        if (!rec->evlist->nr_groups)
                perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
 
@@ -965,9 +974,11 @@ static struct record record = {
        .tool = {
                .sample         = process_sample_event,
                .fork           = perf_event__process_fork,
+               .exit           = perf_event__process_exit,
                .comm           = perf_event__process_comm,
                .mmap           = perf_event__process_mmap,
                .mmap2          = perf_event__process_mmap2,
+               .ordered_events = true,
        },
 };
 
index 37e301a32f437eb6004ba4f4ccc6b90c73b9aa5c..d99d850e1444c9751cdbf7e0552b314e26597fef 100644 (file)
@@ -343,7 +343,7 @@ static int read_counter(struct perf_evsel *counter)
        return 0;
 }
 
-static void read_counters(bool close)
+static void read_counters(bool close_counters)
 {
        struct perf_evsel *counter;
 
@@ -354,7 +354,7 @@ static void read_counters(bool close)
                if (process_counter(counter))
                        pr_warning("failed to process counter %s\n", counter->name);
 
-               if (close) {
+               if (close_counters) {
                        perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
                                             thread_map__nr(evsel_list->threads));
                }
index ecf319728f25d649768e33b3e1f274d04432f3fc..6135cc07213cb0d3379d58033ea87aa8dc580878 100644 (file)
@@ -601,8 +601,8 @@ static void display_sig(int sig __maybe_unused)
 
 static void display_setup_sig(void)
 {
-       signal(SIGSEGV, display_sig);
-       signal(SIGFPE,  display_sig);
+       signal(SIGSEGV, sighandler_dump_stack);
+       signal(SIGFPE, sighandler_dump_stack);
        signal(SIGINT,  display_sig);
        signal(SIGQUIT, display_sig);
        signal(SIGTERM, display_sig);
index 094ddaee104c73d7caae22d851d79629c4715cd3..d31fac19c30b2d298ab2cf3a710b9b27c5764144 100644 (file)
@@ -638,7 +638,7 @@ ifndef DESTDIR
 prefix ?= $(HOME)
 endif
 bindir_relative = bin
-bindir = $(prefix)/$(bindir_relative)
+bindir = $(abspath $(prefix)/$(bindir_relative))
 mandir = share/man
 infodir = share/info
 perfexecdir = libexec/perf-core
index 7629bef2fd791b41f64e49da53bc895e62d3dab4..fa67613976a80147e672bd2b960c9f577ff06b74 100644 (file)
@@ -48,7 +48,7 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
 
 static bool hist_browser__has_filter(struct hist_browser *hb)
 {
-       return hists__has_filter(hb->hists) || hb->min_pcnt;
+       return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter;
 }
 
 static int hist_browser__get_folding(struct hist_browser *browser)
index 586a59d46022a9fc8901807f5c02be4e2551db25..d2d318c59b379531903f775abd9f842a02e01ca8 100644 (file)
@@ -139,10 +139,10 @@ $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
 
-$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c FORCE
+$(OUTPUT)util/rbtree.o: ../lib/rbtree.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
 
-$(OUTPUT)util/hweight.o: ../../lib/hweight.c FORCE
+$(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
index 7e7405c9b9361638f649820ae369bdec64e89c20..83d9dd96fe08ea8c613d1bda4db9b00bf4d04cd9 100644 (file)
@@ -53,11 +53,6 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
 {
        struct perf_event_mmap_page *pc = userpg;
 
-#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
-       pr_err("Cannot use AUX area tracing mmaps\n");
-       return -1;
-#endif
-
        WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
 
        mm->userpg = userpg;
@@ -73,6 +68,11 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
                return 0;
        }
 
+#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
+       pr_err("Cannot use AUX area tracing mmaps\n");
+       return -1;
+#endif
+
        pc->aux_offset = mp->offset;
        pc->aux_size = mp->len;
 
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
deleted file mode 100644 (file)
index f06d89f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __TOOLS_LINUX_PERF_RBTREE_H
-#define __TOOLS_LINUX_PERF_RBTREE_H
-#include <stdbool.h>
-#include "../../../../include/linux/rbtree.h"
-
-/*
- * Handy for checking that we are not deleting an entry that is
- * already in a list, found in block/{blk-throttle,cfq-iosched}.c,
- * probably should be moved to lib/rbtree.c...
- */
-static inline void rb_erase_init(struct rb_node *n, struct rb_root *root)
-{
-       rb_erase(n, root);
-       RB_CLEAR_NODE(n);
-}
-#endif /* __TOOLS_LINUX_PERF_RBTREE_H */
diff --git a/tools/perf/util/include/linux/rbtree_augmented.h b/tools/perf/util/include/linux/rbtree_augmented.h
deleted file mode 100644 (file)
index 9d6fcdf..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#include <stdbool.h>
-#include "../../../../include/linux/rbtree_augmented.h"
index 7ff682770fdb16e71b368af16efad0edd9443d87..f1a4c833121e306a364851328f6409cb22d779eb 100644 (file)
@@ -1387,6 +1387,24 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
                                                        event->fork.ptid);
        int err = 0;
 
+       if (dump_trace)
+               perf_event__fprintf_task(event, stdout);
+
+       /*
+        * There may be an existing thread that is not actually the parent,
+        * either because we are processing events out of order, or because the
+        * (fork) event that would have removed the thread was lost. Assume the
+        * latter case and continue on as best we can.
+        */
+       if (parent->pid_ != (pid_t)event->fork.ppid) {
+               dump_printf("removing erroneous parent thread %d/%d\n",
+                           parent->pid_, parent->tid);
+               machine__remove_thread(machine, parent);
+               thread__put(parent);
+               parent = machine__findnew_thread(machine, event->fork.ppid,
+                                                event->fork.ptid);
+       }
+
        /* if a thread currently exists for the thread id remove it */
        if (thread != NULL) {
                machine__remove_thread(machine, thread);
@@ -1395,8 +1413,6 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
 
        thread = machine__findnew_thread(machine, event->fork.pid,
                                         event->fork.tid);
-       if (dump_trace)
-               perf_event__fprintf_task(event, stdout);
 
        if (thread == NULL || parent == NULL ||
            thread__fork(thread, parent, sample->time) < 0) {
index e23ded40c79e3ecd62642bf2a07a34c5fc7662f8..0766d98c5da59dd1aa44c41aaee1791502ac9a0d 100644 (file)
@@ -10,7 +10,7 @@ util/ctype.c
 util/evlist.c
 util/evsel.c
 util/cpumap.c
-../../lib/hweight.c
+../lib/hweight.c
 util/thread_map.c
 util/util.c
 util/xyarray.c
@@ -19,5 +19,5 @@ util/rblist.c
 util/stat.c
 util/strlist.c
 util/trace-event.c
-../../lib/rbtree.c
+../lib/rbtree.c
 util/string.c
index 53e8bb7bc8521a09f1347d48de2a0dd1eeb5e0bc..2a5d8d7698aedb8c82bdf8488f1fb62ded5b438a 100644 (file)
@@ -85,7 +85,7 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
        else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
                update_stats(&runtime_cycles_stats[ctx][cpu], count[0]);
        else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
-               update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
+               update_stats(&runtime_cycles_in_tx_stats[ctx][cpu], count[0]);
        else if (perf_stat_evsel__is(counter, TRANSACTION_START))
                update_stats(&runtime_transaction_stats[ctx][cpu], count[0]);
        else if (perf_stat_evsel__is(counter, ELISION_START))
@@ -398,20 +398,18 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
                                " #   %5.2f%% aborted cycles         ",
                                100.0 * ((total2-avg) / total));
        } else if (perf_stat_evsel__is(evsel, TRANSACTION_START) &&
-                  avg > 0 &&
                   runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
                total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
 
-               if (total)
+               if (avg)
                        ratio = total / avg;
 
                fprintf(out, " # %8.0f cycles / transaction   ", ratio);
        } else if (perf_stat_evsel__is(evsel, ELISION_START) &&
-                  avg > 0 &&
                   runtime_cycles_in_tx_stats[ctx][cpu].n != 0) {
                total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
 
-               if (total)
+               if (avg)
                        ratio = total / avg;
 
                fprintf(out, " # %8.0f cycles / elision       ", ratio);
index 48b588c6951a9476246d6c71a9ee7b8535a8be37..60f11414bb5c8c6b463980f7b767662654e0331d 100644 (file)
@@ -1911,6 +1911,8 @@ int setup_list(struct strlist **list, const char *list_str,
                pr_err("problems parsing %s list\n", list_name);
                return -1;
        }
+
+       symbol_conf.has_filter = true;
        return 0;
 }
 
index bef47ead1d9bd1efc5e9620f04b13714286ff616..b98ce51af1422f8e22415d6a104b4a19810940cc 100644 (file)
@@ -105,7 +105,8 @@ struct symbol_conf {
                        demangle_kernel,
                        filter_relative,
                        show_hist_headers,
-                       branch_callstack;
+                       branch_callstack,
+                       has_filter;
        const char      *vmlinux_name,
                        *kallsyms_name,
                        *source_prefix,
index 28c4b746baa19bef9830814c4fe7c69f1be0b06b..0a9ae8014729c085ffd2872e2bc13871f79c9908 100644 (file)
@@ -191,6 +191,12 @@ static int thread__clone_map_groups(struct thread *thread,
        if (thread->pid_ == parent->pid_)
                return 0;
 
+       if (thread->mg == parent->mg) {
+               pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
+                        thread->pid_, thread->tid, parent->pid_, parent->tid);
+               return 0;
+       }
+
        /* But this one is new process, copy maps. */
        for (i = 0; i < MAP__NR_TYPES; ++i)
                if (map_groups__clone(thread->mg, parent->mg, i) < 0)
index da7646d767feba14c4f1ad3ba60f3758d5f89413..292ae2c90e063d958da5f5859787c4c1c70ccab5 100644 (file)
@@ -136,8 +136,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
                if (grow) {
                        struct thread_map *tmp;
 
-                       tmp = realloc(threads, (sizeof(*threads) +
-                                               max_threads * sizeof(pid_t)));
+                       tmp = thread_map__realloc(threads, max_threads);
                        if (tmp == NULL)
                                goto out_free_namelist;
 
index 4b89118f158db458ae29cca6d20b093d81392cf6..44d440da15dcf73f97a81518c97a33be5c32b89b 100644 (file)
@@ -236,18 +236,16 @@ static struct dso *__machine__findnew_compat(struct machine *machine,
        const char *file_name;
        struct dso *dso;
 
-       pthread_rwlock_wrlock(&machine->dsos.lock);
        dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true);
        if (dso)
-               goto out_unlock;
+               goto out;
 
        file_name = vdso__get_compat_file(vdso_file);
        if (!file_name)
-               goto out_unlock;
+               goto out;
 
        dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);
-out_unlock:
-       pthread_rwlock_unlock(&machine->dsos.lock);
+out:
        return dso;
 }
 
index 8e9b64520ec1096c4ffe508970fe41db36fe04e6..f56914c7929b80169efc6f3079cb1b1fae8cd269 100644 (file)
@@ -1,3 +1,6 @@
+ldflags-y += --wrap=ioremap_wt
+ldflags-y += --wrap=ioremap_wc
+ldflags-y += --wrap=devm_ioremap_nocache
 ldflags-y += --wrap=ioremap_cache
 ldflags-y += --wrap=ioremap_nocache
 ldflags-y += --wrap=iounmap
index c85a6f6ba5593e0cdf1834cc314c136a6d339fff..64bfaa50831ccd99f999ebb08fbb35eb0248820c 100644 (file)
@@ -65,6 +65,21 @@ void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size,
        return fallback_fn(offset, size);
 }
 
+void __iomem *__wrap_devm_ioremap_nocache(struct device *dev,
+               resource_size_t offset, unsigned long size)
+{
+       struct nfit_test_resource *nfit_res;
+
+       rcu_read_lock();
+       nfit_res = get_nfit_res(offset);
+       rcu_read_unlock();
+       if (nfit_res)
+               return (void __iomem *) nfit_res->buf + offset
+                       - nfit_res->res->start;
+       return devm_ioremap_nocache(dev, offset, size);
+}
+EXPORT_SYMBOL(__wrap_devm_ioremap_nocache);
+
 void __iomem *__wrap_ioremap_cache(resource_size_t offset, unsigned long size)
 {
        return __nfit_test_ioremap(offset, size, ioremap_cache);
@@ -77,6 +92,18 @@ void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size)
 }
 EXPORT_SYMBOL(__wrap_ioremap_nocache);
 
+void __iomem *__wrap_ioremap_wt(resource_size_t offset, unsigned long size)
+{
+       return __nfit_test_ioremap(offset, size, ioremap_wt);
+}
+EXPORT_SYMBOL(__wrap_ioremap_wt);
+
+void __iomem *__wrap_ioremap_wc(resource_size_t offset, unsigned long size)
+{
+       return __nfit_test_ioremap(offset, size, ioremap_wc);
+}
+EXPORT_SYMBOL(__wrap_ioremap_wc);
+
 void __wrap_iounmap(volatile void __iomem *addr)
 {
        struct nfit_test_resource *nfit_res;
index 4b69b8368de01feb32b5521835efed0b8d372148..d0bdae40ccc9033aae0e9695943d4ce5367bde33 100644 (file)
@@ -128,6 +128,8 @@ struct nfit_test {
        int num_pm;
        void **dimm;
        dma_addr_t *dimm_dma;
+       void **flush;
+       dma_addr_t *flush_dma;
        void **label;
        dma_addr_t *label_dma;
        void **spa_set;
@@ -155,7 +157,7 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
        int i, rc;
 
        if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
-               return -ENXIO;
+               return -ENOTTY;
 
        /* lookup label space for the given dimm */
        for (i = 0; i < ARRAY_SIZE(handle); i++)
@@ -331,7 +333,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
                        + sizeof(struct acpi_nfit_system_address) * NUM_SPA
                        + sizeof(struct acpi_nfit_memory_map) * NUM_MEM
                        + sizeof(struct acpi_nfit_control_region) * NUM_DCR
-                       + sizeof(struct acpi_nfit_data_region) * NUM_BDW;
+                       + sizeof(struct acpi_nfit_data_region) * NUM_BDW
+                       + sizeof(struct acpi_nfit_flush_address) * NUM_DCR;
        int i;
 
        t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma);
@@ -356,6 +359,10 @@ static int nfit_test0_alloc(struct nfit_test *t)
                if (!t->label[i])
                        return -ENOMEM;
                sprintf(t->label[i], "label%d", i);
+
+               t->flush[i] = test_alloc(t, 8, &t->flush_dma[i]);
+               if (!t->flush[i])
+                       return -ENOMEM;
        }
 
        for (i = 0; i < NUM_DCR; i++) {
@@ -408,6 +415,7 @@ static void nfit_test0_setup(struct nfit_test *t)
        struct acpi_nfit_system_address *spa;
        struct acpi_nfit_control_region *dcr;
        struct acpi_nfit_data_region *bdw;
+       struct acpi_nfit_flush_address *flush;
        unsigned int offset;
 
        nfit_test_init_header(nfit_buf, size);
@@ -831,6 +839,39 @@ static void nfit_test0_setup(struct nfit_test *t)
        bdw->capacity = DIMM_SIZE;
        bdw->start_address = 0;
 
+       offset = offset + sizeof(struct acpi_nfit_data_region) * 4;
+       /* flush0 (dimm0) */
+       flush = nfit_buf + offset;
+       flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
+       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->device_handle = handle[0];
+       flush->hint_count = 1;
+       flush->hint_address[0] = t->flush_dma[0];
+
+       /* flush1 (dimm1) */
+       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 1;
+       flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
+       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->device_handle = handle[1];
+       flush->hint_count = 1;
+       flush->hint_address[0] = t->flush_dma[1];
+
+       /* flush2 (dimm2) */
+       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 2;
+       flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
+       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->device_handle = handle[2];
+       flush->hint_count = 1;
+       flush->hint_address[0] = t->flush_dma[2];
+
+       /* flush3 (dimm3) */
+       flush = nfit_buf + offset + sizeof(struct acpi_nfit_flush_address) * 3;
+       flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
+       flush->header.length = sizeof(struct acpi_nfit_flush_address);
+       flush->device_handle = handle[3];
+       flush->hint_count = 1;
+       flush->hint_address[0] = t->flush_dma[3];
+
        acpi_desc = &t->acpi_desc;
        set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
        set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
@@ -933,6 +974,10 @@ static int nfit_test_probe(struct platform_device *pdev)
                                GFP_KERNEL);
                nfit_test->dimm_dma = devm_kcalloc(dev, num, sizeof(dma_addr_t),
                                GFP_KERNEL);
+               nfit_test->flush = devm_kcalloc(dev, num, sizeof(void *),
+                               GFP_KERNEL);
+               nfit_test->flush_dma = devm_kcalloc(dev, num, sizeof(dma_addr_t),
+                               GFP_KERNEL);
                nfit_test->label = devm_kcalloc(dev, num, sizeof(void *),
                                GFP_KERNEL);
                nfit_test->label_dma = devm_kcalloc(dev, num,
@@ -943,7 +988,8 @@ static int nfit_test_probe(struct platform_device *pdev)
                                sizeof(dma_addr_t), GFP_KERNEL);
                if (nfit_test->dimm && nfit_test->dimm_dma && nfit_test->label
                                && nfit_test->label_dma && nfit_test->dcr
-                               && nfit_test->dcr_dma)
+                               && nfit_test->dcr_dma && nfit_test->flush
+                               && nfit_test->flush_dma)
                        /* pass */;
                else
                        return -ENOMEM;
index 7f0c756993af15a0b5cb99ba50dd6f7d0dfca226..3d7dc6afc3f8f9459ca407ee5a16b1b2c9a8119b 100644 (file)
@@ -191,7 +191,7 @@ int main(int argc, char *argv[])
                if (res > 0) {
                        atomic_set(&requeued, 1);
                        break;
-               } else if (res > 0) {
+               } else if (res < 0) {
                        error("FUTEX_CMP_REQUEUE_PI failed\n", errno);
                        ret = RET_ERROR;
                        break;
index 620e37f741b868a231a414a71511cd8872704a3c..1dd087da6f31ae2f38c70042213ee6e5159cee10 100644 (file)
@@ -155,6 +155,8 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
                list_add_tail(&kvg->node, &kv->group_list);
                kvg->vfio_group = vfio_group;
 
+               kvm_arch_start_assignment(dev->kvm);
+
                mutex_unlock(&kv->lock);
 
                kvm_vfio_update_coherency(dev);
@@ -190,6 +192,8 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
                        break;
                }
 
+               kvm_arch_end_assignment(dev->kvm);
+
                mutex_unlock(&kv->lock);
 
                kvm_vfio_group_put_external_user(vfio_group);
@@ -239,6 +243,7 @@ static void kvm_vfio_destroy(struct kvm_device *dev)
                kvm_vfio_group_put_external_user(kvg->vfio_group);
                list_del(&kvg->node);
                kfree(kvg);
+               kvm_arch_end_assignment(dev->kvm);
        }
 
        kvm_vfio_update_coherency(dev);